长度分别为\(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;
}
CF1540C2. Converging Array (Hard Version)
原文:https://www.cnblogs.com/jz-597/p/14956202.html