CF1540C2. Converging Array (Hard Version)

长度分别为\(n\)\(n-1\)的数组\(a_i,b_i\)

\(a_i\)进行无限次操作:随机选择\(i\in [1,n)\),令\(a_i= \min(a_i,\frac{a_i+a_{i+1}-b_i}{2}),a_{i+1}=\max(a_{i+1},\frac{a_i+a_{i+1}+b_i}{2})\)

可证\(a_i\)收敛。

\(F(a,b)\)表示\(a_1\)收敛的结果。

给定\(b_i\)\(c_i\)(表示\(a_i\in[0,c_i]\))。\(Q\)次询问,每次问\(F(a,b)\ge x\)\(a_i\)的方案数。


考虑一次有变化的操作的条件,发现不管是\(min\)还是\(max\)都是\(b_i>a_{i+1}-a_i\)

\(t_i=a_{i+1}-a_i\)。发现一次操作相当于:如果\(t_i<b_i\)\(t_{i-1}+=\frac{t_i-b_i}{2},t_{i+1}+=\frac{t_i-b_i}{2},t_i=b_i\)

形象一下:可以看成\(t_i\)多出\(b_i\)的部分(尽管是负的)平均分配到两边,微分一下,某个\(\epsilon\)\(t_i<b_i\)的时候可以向左右等概率随机游走。要么随机到\(t_i\ge b_i\),要么掉到\(t_0\)\(t_n\)

如果\(\forall t_i\le b_i\),感受到最终会变成所有\(t_i=b_i\)\(i\in[1,n)\)),答案即\(t_0\)很好求。扩展到所有情况,发现:只需要枚举\(L=[1,n]\),只考虑\((0,L)\)(此时忽略\(t_i<b_i\)的限制),不能操作\(t_0\)\(t_L\),此时\(t_0\)。枚举\(L\)\(t_0\)的最小值,就是\(t_0\)真正的值。

证明考虑在算\(L\)的时候,考虑\((0,L)\)。如果事实上\((0,L-1)\)中最终出现了坑(即\(t_i>b_i\)的位置),那么一定存在某个前缀算过正确答案,并前缀保留了它作为答案。如果到最后\(t_{L-1}=b_{L-1}\),那么在过程中\(t_{L-1}\)可能为填坑作出过贡献但没有将坑填完(否则就是下一种情况),因为坑没填完所以贡献不到\(t_0\)所以不会更新答案;否则有正贡献不更新答案。如果最终没有出现坑,如果到最后\(t_{L-1}=b_{L-1}\)则有负贡献能更新答案;否则产生新坑有正贡献不更新答案。

考虑带吸收壁的随机游走问题。一个长度为\(L\)的线段上,到点\(0\)和点\(L\)结束,考虑到\(0\)的概率。设\(f_i\)\(f_0=1,f_L=0,f_i=\frac{f_{i-1}+f_{i+1}}{2}\),显然\(f_i=\frac{L-i}{L}\)

于是条件为:\(t_0+\min_L \sum_{i=1}^{L-1}(t_i-b_i)\frac{L-i}{L}\ge x\)

展开一下,发现其实就是:\(\forall L,\sum_{i=1}^L a_i\ge Lx+\sum_{i=1}^{L-1}b_i(L-i)\)

DP记一下前缀和。直接做\(O(n^2V^2)\),可以用前缀和优化至\(O(n^2V)\)

然后观察下哪些\(x\)是“有用的”。令\(h_L=Lx+\sum_{i=1}^{L-1}b_i(L-i)\)。首先如果有解就要\(\forall L,Lx+h_L\le LV\),即\(x\le V-\max{\frac{h_L}{L}}\)。另外如果\(\forall Lx+h_L<0\),则答案和\(x\)的取值无关,算一下\(x<-\max\frac{h_L}{L}\),夹在两者之间的只有\(O(V)\)个。于是只需要算\(O(V)\)\(x\)的答案即可。


using namespace std;
#include <bits/stdc++.h>
const int N=105,mo=1000000007;
typedef long long ll;
int n;
int c[N],b[N];
int sc[N],sb0[N],sb1[N],h[N];
int lim;
int f[N][N*N],g[N*N];
int ans[N];
int solve(){
	memset(f,0,sizeof f);
	f[0][0]=1;
	for (int i=1;i<=n;++i){
		ll ps=0;
		for (int s=0;s<=sc[i];++s)
			g[s]=(ps+=f[i-1][s])%=mo;
		for (int s=sc[i];s>c[i];--s)
			g[s]=(g[s]-g[s-c[i]-1]+mo)%mo;
		int t=max(lim*i+h[i],0);
		for (int s=t;s<=sc[i];++s)
			f[i][s]=g[s];
	}
	ll ans=0;
	for (int s=0;s<=sc[n];++s)
		ans+=f[n][s];
	ans%=mo;
	return ans;
}
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1;i<=n;++i){
		scanf("%d",&c[i]);
		sc[i]=sc[i-1]+c[i];
	}
	for (int i=1;i<n;++i)
		scanf("%d",&b[i]);
	int mx=INT_MIN;
	for (int i=1;i<=n;++i){
		sb0[i]=sb0[i-1]+b[i];
		sb1[i]=sb1[i-1]+b[i]*i;
		h[i]=sb0[i]*i-sb1[i];
		mx=max(mx,(h[i]+i-1)/i);
	}
	for (int i=0;i<=101;++i)
		lim=i-mx,ans[i]=solve();
	int Q;
	scanf("%d",&Q);
	while (Q--){
		scanf("%d",&lim);
		lim=min(max(lim,0-mx),101-mx);
		printf("%d\n",ans[lim+mx]);
	}
	return 0;
}
posted @ 2021-06-30 20:03  jz_597  阅读(108)  评论(0编辑  收藏  举报