【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;
}