时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Ho得到了一个数组作为他的新年礼物,他非常喜欢这个数组!
在仔细研究了几天之后,小Ho成功的将这个数组拆成了若干段,并且每段的和都不为0!
现在小Ho希望知道,这样的拆分方法一共有多少种?
两种拆分方法被视作不同,当且仅当数组断开的所有位置组成的集合不同。
输入
每组输入的第一行为一个正整数N,表示这个数组的长度
第二行为N个整数A1~AN,描述小Ho收到的这个数组
对于40%的数据,满足1<=N<=10
对于100%的数据,满足1<=N<=105, |Ai|<=100
输出
对于每组输入,输出一行Ans,表示拆分方案的数量除以(109+7)的余数。
样例输入
5
1 -1 0 2 -2
样例输出
5
dalao 思路:http://hihocoder.com/discuss/question/5645
开始很容易直接想到一个O(n^2) 的动态规划。 令dp[i]表示i个数不同种划分数,sum[j,i]表示数组下标从j到i的和。 从划分思想,比较容易想到:
dp[i]=∑dp[j] (j<i&&sum[j,i]!=0)
其中sum[j,i]可以由前缀数组O(1)的得到。
但明显这题N<1e5,复杂度不够。 继续优化。 对于dp[i]求和这一步我们同样用前缀数组优化。 定义: dp_sum[i] = ∑ dp[i]
那么对于dp[i] = dp_sum[i-1] - 数量(∑ sum[j+1,i]=0)
。
对于sum[j+1,i]=0
,我们两边同时加上sum[0,j],就变成:sum[0,i] = sum[0,j]
。问题变成减去出现sum[0,i] = sum[0,j]
的数量,也就是减去前缀和为sum[0,i]
的数量。 ``于是我们只需要一个Hash表去保存前缀和sum[0,i]
出现的个数。时间复杂度O(1)求出sum[0,i]
的数量。
则转移方程:dp[i] = dp_sum[i-1] - Hash[sum[0,i]]
o(n^2) 复杂度 超时
package Daily;
import java.util.Scanner;
public class Main_233 {
int mod = 1000000007;
public void excute(){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int []nums = new int[n];
for(int i = 0; i < n; i++){
nums[i] = sc.nextInt();
}
sc.close();
int count = find(nums);
System.out.println(count);
}
public int find(int []nums){
int dp[] = new int[nums.length + 1];
dp[nums.length] = 1;
for(int i = nums.length- 1; i >= 0; i --){
int subSum = 0;
int kind = 0;
for(int k = i; k < nums.length ; k ++){
subSum += nums[k];
if(subSum != 0 ){
kind += dp[k +1];
}
}
dp[i] = kind;
}
return dp[0];
}
public static void main(String[] args){
Main_233 m = new Main_233();
m.excute();
}
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
const int mod= 1e9+7;
ll dp[N],sum[N],sum_dp[N];
map<ll,ll> Hash;
int main(){
int n;
while(~scanf("%d",&n)){
memset(dp,0,sizeof(dp));
sum[0] = 0;
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
sum[i] = sum[i-1] + x;
}
dp[0] = 1;
sum_dp[0] = 1;
Hash[0] = 1;
for(int i=1;i<=n;i++){
dp[i] = (sum_dp[i-1] - Hash[sum[i]] + mod)%mod;
sum_dp[i] = (sum_dp[i-1] + dp[i] + mod)%mod;
Hash[sum[i]] = (Hash[sum[i]] +dp[i] + mod)%mod;
//cout<<dp[i]<<" ";
}
//cout<<endl;
printf("%lld\n",dp[n]);
}
}