题目概述
给定一个整数数组 \(b_1, b_2, \ldots, b_n\)。
如果一个整数数组 \(a_1, a_2, \ldots, a_n\) 满足对于每个 \(i\)(\(1 \leq i \leq n\)),至少满足以下两个条件之一:
- \(b_i = a_i\),或者
- \(b_i = \sum_{j=1}^{i} a_j\),
则称该数组为“混合数组”。
请你计算有多少个“混合数组” \(a_1, a_2, \ldots, a_n\)。由于答案可能很大,请输出对 \(10^9 + 7\) 取模后的结果。
数据范围:\(1\leq n\leq 10^5\)。
分析
套路地设 \(f_{i,j}\) 表示前 \(i\) 个都填了其和 \(j\) 的方案。
有:
- \(a_i=b_i\),所以 \(f_{i,j}=f_{i-1,j-b_i}\)。
- \(b_i=\sum a_j\),所以 \(f_{i,b_i}=f_{i-1,x}\),其中 \(x\) 为任意数。
考虑到这样存会炸,而 \(x\) 显然只是和出现过的数相关,直接用 \(map\)。
第一个情况相当于位移,第二个情况相当于全局和。
所以考虑维护全局和,第一种情况对全局和不会造成影响,而第二种情况会对全局和贡献上一个的全局和除开上一个本身(应为第二种情况需要覆盖第一种情况)。
直接做就行了。
代码
时间复杂度 \(\mathcal{O}(n\log n)\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <map>
#define int long long
// #define N
using namespace std;
const int mod = 1e9 + 7;
map<int,int> f;
signed main(){int T;cin >> T;for (;T--;) {f.clear();int n,res = 0,ans;ans = f[0] = 1;scanf("%lld",&n);for (int x;n --;) {scanf("%lld",&x);int val = ans - f[res];f[res] = ans;ans = ((ans + val) % mod + mod) % mod;res -= x;}printf("%lld\n",ans);}return 0;
}