长度分别为(n)和(n-1)的数组(a_i,b_i)。
对(a_i)进行无限次操作:随机选择(iin [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_iin[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_ige b_i),要么掉到(t_0)或(t_n)。
如果(forall t_ile b_i),感受到最终会变成所有(t_i=b_i)((iin[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_ige 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_Lle LV),即(xle V-max{frac{h_L}{L}})。另外如果(forall Lx+h_L<0),则答案和(x)的取值无关,算一下(x<-maxfrac{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
",ans[lim+mx]);
}
return 0;
}