罗勇军 →《算法竞赛·快冲300题》每日一题:“乘积” ← 动态规划

【题目来源】
http://oj.ecustacm.cn/problem.php?id=1781
http://oj.ecustacm.cn/viewnews.php?id=1023

【题目描述】
给你一个长度为 n 的序列,序列中的元素只包括 1 和 -1。
请问有多少个连续的子序列乘积为正数。

【输入格式】
输入第一行为正整数 n。(n不超过10^6)
第二行包含 n 个整数。

【输出格式】
输出一个数字表示答案。

【输入样例】
4
1 1 -1 -1

【输出样例】
6

【算法分析】
● 动态规划
最后一步法:https://blog.csdn.net/hnjzsyjyj/article/details/112797538

本题是“
计数型”问题,可采用动态规划算法求解。
(1)确立状态
设输入的序列是 a[1]~a[n],依据最后一步法,可定义 DP 状态为:

f[i][0]:以 a[i] 结尾的积为 -1 的连续子序列个数
f[i][1]:以 a[i] 结尾的积为 1 的连续子序列个数

例如,针对样例 {1, 1, -1, -1},有 f[1][1]=1,f[2][1]=2,f[3][1]=0,f[4][1]=3。
(2)状态转移方程
若a[i]=1:

f[i][1]=f[i-1][1]+1,积为 1 的连续子序列个数加 1
f[i][0]=f[i-1][0],积继续为 -1

若a[i]=-1:
f[i][1]=f[i-1][0]
f[i][0]=f[i-1][1]+1

最后,把所有 f[i][1] 相加,就是答案。

【算法代码】

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6+5;
int a[maxn];
long long f[maxn][2];
long long ans;

int main() {
    int n;
    cin>>n;
    for(int i=1; i<=n; i++) cin>>a[i];

    for(int i=1; i<=n; i++) {
        if(a[i]==1) {
            f[i][1]=f[i-1][1]+1;
            f[i][0]=f[i-1][0];
        } else if(a[i]==-1) {
            f[i][1]=f[i-1][0];
            f[i][0]=f[i-1][1]+1;
        }
    }

    for(int i=1; i<=n; i++) ans=ans+f[i][1];
    cout<<ans<<endl;

    return 0;
}


/*
in:
4
1 1 -1 -1

out:
6
*/



【参考文献】
https://blog.csdn.net/weixin_43914593/article/details/131810636
https://blog.csdn.net/hnjzsyjyj/article/details/112797538




 

猜你喜欢

转载自blog.csdn.net/hnjzsyjyj/article/details/132439574