【HihoCoder 1475 --- 数组分拆】前缀和+思维递推

【HihoCoder 1475 --- 数组分拆】前缀和+思维递推

题目来源:点击进入【HihoCoder 1475 — 数组分拆】

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

解题思路

通过sum[i]来记录前i个的和。
通过dp[i]来记录[0,i]中满足题意的分配方法数。
通过m[x]来记录前i项和为x的次数。
cnt记录i-1项时总的方案数。

首先当我们计算第i项时,我们第i位可以和前面所有方案的最后一段合并,或者自己单独成为一段。但是根据题意我们需要去掉中间和为0的方案,所以减去m[sum[i]]。所以dp[i]=(cnt+1)-m[sum[i]]。

然后更新cnt,使其记录前i项总共的方案数。即cnt+=dp[i]。
并且更新和为sum[i]的方案数。

AC代码(C++):

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <map>
#define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e5+5;
const int MOD = 1e9+7;
int sum[MAXN],dp[MAXN];

int main(){
    SIS;
    int n,cnt=0;
    map<int,int> m;
    m[0]=1;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> sum[i];
        sum[i]+=sum[i-1];
        dp[i]=(cnt+1-m[sum[i]]+MOD)%MOD;
        cnt=(cnt+dp[i])%MOD;
        m[sum[i]]=(m[sum[i]]+dp[i])%MOD;
    }
    cout << dp[n] << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章