100道动态规划——39 hihoCoder 1475 数组拆分 前缀和 DP

#1475 : 数组分拆

Time Limit: 10000ms
Case Time Limit: 1000ms
Memory Limit: 256MB

Description

小Ho得到了一个数组作为他的新年礼物,他非常喜欢这个数组!

在仔细研究了几天之后,小Ho成功的将这个数组拆成了若干段,并且每段的和都不为0!

现在小Ho希望知道,这样的拆分方法一共有多少种?

两种拆分方法被视作不同,当且仅当数组断开的所有位置组成的集合不同。

Input

每组输入的第一行为一个正整数N,表示这个数组的长度

第二行为N个整数A1~AN,描述小Ho收到的这个数组

对于40%的数据,满足1<=N<=10

对于100%的数据,满足1<=N<=105, |Ai|<=100

Output

对于每组输入,输出一行Ans,表示拆分方案的数量除以(109+7)的余数。

Sample Input
5
1 -1 0 2 -2
Sample Output
5


        显然n^2算法是过不了的。。但是我连n^2算法都没有想出来。。。。

        n^2算法是这样的,定义状态dp[i]表示目前考虑到数组的第i位且合法的方案数,定义数组sum[i,j]表示数组下标从i~j的元素之和

        因此dp[i]=∑dp[j] (j

        这个是正确性是显然的,只要sum[j,i]不等于0的话,就可以沿用之前的方案

        优化到O(n)的做法是使用前缀和

        对sum[j,i]进行变形,左右两边同时加上sum[0,j-1],这就变成了sum[0,i]!=sum[0,j-1],这就是前缀和

        定义一个map表示每种前缀和对应的方案数,用一个tot来表示所用的方案总数,于是dp[i]就可以通过tot-map[sum[0,i]]直接计算出来,这样计算完之后同时更新map[sum[0,i]]和tot。

        实际上sum数组是不需要的,因为我们是从前向后计算,且每一次只需要上一次的值,因此实际上用一个变量存储当前的前缀和即可

        PS:本来我是压在一行里写的,但是为了方便你们看,我特意换行了,注意for循环每句话的后面是逗号


#include 
#include 
#include 
#include 

using namespace std;
typedef long long ll;
const ll mod = 1E9+7,maxm=1E5+10;

ll n,tmp,dp[maxm]{1},tot=1;
map ma;

int main(){
    ios_base::sync_with_stdio(0);
    cin>>n;
    ma[0]=1;
    for(int i=0,x;i>x,tmp+=x,
        dp[i]=(tot-ma[tmp]+mod)%mod,
        ma[tmp]=(ma[tmp]+dp[i])%mod,
        tot=(tot+dp[i])%mod;
    cout<


你可能感兴趣的:(我说过的,CCPC拿到铜了,就做100道动态规划,CCPC拿到铜了,就做100道动态规划,我说过的,100道动态规划)