• CF1540C2. Converging Array (Hard Version)


    长度分别为(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;
    }
    
  • 相关阅读:
    HTTP请求方法 GET POST【总结】
    Data Binding MVVM 数据绑定 总结
    Butter Knife 黄油刀
    原生JS强大DOM选择器querySelector与querySelectorAll
    JS日期Date详解与实例扩展
    JS中的冒泡排序以及实现一个数组中得最到最大的数字小例
    jquery.roundabout.js实现3D图片层叠旋转木马切换
    AngularJS 表格
    AngularJS XMLHttpRequest
    AngularJS Filters
  • 原文地址:https://www.cnblogs.com/jz-597/p/14956202.html
Copyright © 2020-2023  润新知