hihocoder offer收割编程练习赛8 C 数组分拆

思路:(引自bfsoyc的回答:http://hihocoder.com/discuss/question/4160

动态规划。状态dp[i]表示 前i个数的合法的方案数,转移是

dp[i] = sum{ dp[k] | 1 < k < i && sum(k+1,i)!=0 }

        = sum{ dp[k] | 1 < k < i } - sum{ dp[k] | 1 < k < i && sum(k+1,i)==0 }

关键是求后半部分怎么找到sum(k+1,i)==0 的k, 等价于找 prefixSum(k)== prefixSum(i),因为这里前缀比后缀维护容易。利用容器map M, M[ps] = sum{dp[k] | prefixSum(k)==ps }。 那么 dp[i] = sum{ dp[k] | 1 < k < i } - M[prefixSum(i)]。

实现:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <map>
 4 using namespace std;
 5 
 6 const int mod = 1e9 + 7;
 7 int a[100005], s[100005], dp[100005], n, total;
 8 map<int, int> g;
 9 
10 int solve()
11 {
12     total = dp[0] = 1;
13     g[0] = 1;
14     for (int i = 1; i <= n; i++)
15     {
16         if (!g.count(s[i]))
17             g[s[i]] = 0;
18         dp[i] = ((total - g[s[i]]) % mod + mod) % mod;
19         g[s[i]] = (g[s[i]] + dp[i]) % mod;
20         total = (total + dp[i]) % mod;
21     }
22     return dp[n];
23 }
24 
25 int main()
26 {
27     cin >> n;
28     for (int i = 1; i <= n; i++)
29     {
30         scanf("%d", &a[i]);
31         s[i] = s[i - 1] + a[i];
32     }
33     cout << solve() << endl;
34     return 0;
35 }
原文地址:https://www.cnblogs.com/wangyiming/p/6542660.html