思路:(引自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 }