CF1485F Copy or Prefix Sum 题解
Problem
传送门:CF1485F Copy or Prefix Sum
给出一个长度为 \(n\) 的序列 \(b_1,b_2,\dots ,b_n\) ,求出有多少种序列\(a_1,a_2,\dots,a_n\) 满足:
\(\forall i \in [1,n],b_i = a_i \or b_i = \sum_\limits{j=1}^i a_j\).
Sol
考虑当前我们填到第 \(i\) 位,所填的数的和是 \(S\) , 那么,我们可以填:
1.\(b_i\)
2.\(b_i-S\)
于是,我们可以记\(dp_i\) 代表当前填的数之和为 \(i\) 的方案数,于是,两种操作对应这:
1.\(dp_{i+b_i} = dp_i\)
2.\(dp_{b_i} = \sum_\limits{j=-\inf}^\inf{dp_j}\)
但是要注意,当 \(b_i = b_i - S\) 也就是 \(S = 0\) 时,是只能算一遍的,减去 \(dp_0\) 即可。
然后维护一个 \(map\) ,代表 \(DP\) 数组,维护一个 \(totadd\) ,代表全局移位(因为有操作一),再维护一个目前的 \(ans\),就搞完了。
Code
#define in read()
int read(){int x = 0,sgn = 1;char ch = getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')sgn=-1;for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);return x*sgn;}
const int N = 2e5+10;
const int mod = 1e9+7;
int n,b[N];
void solve(){
n = in;for(int i = 1;i <= n;i++) b[i] = in;
map<ll,ll> f; f.clear();
f[0] = 1; ll totadd = 0,ans = 1;
for(int i = 1;i <= n;i++){
ll tmp; tmp = (ans - f[-totadd] + mod)% mod; ans = (ans + tmp) % mod; (f[-totadd] += tmp) %= mod;
totadd += b[i];
}ans = (ans + mod) %mod;
printf("%lld\n",ans);
}
int main(){
int test = in;
while(test--) solve();
return 0;
}
彩蛋
1.出题人说 "F is easier than C."确实。
- 于是我打完 C 后开始搞 F
- 搞完了 F,确实是正解,但是已经 0 :53 了,比赛已经结束了 3 分钟
- 其实 F 早就搞完了,有两个神奇的错误调了一会儿,Can you guess ?
本博客作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,转载时请注明出处,谢谢支持!