陣列分拆
時間限制: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 ; i --){ 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]);
}
}