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."确实。

  1. 于是我打完 C 后开始搞 F
  2. 搞完了 F,确实是正解,但是已经 0 :53 了,比赛已经结束了 3 分钟
  3. 其实 F 早就搞完了,有两个神奇的错误调了一会儿,Can you guess ?
posted @ 2021-02-13 08:56  Werner_Yin  阅读(163)  评论(0编辑  收藏  举报