• 杂题集萃[5]


    题意

    给出一个长度为 (N) 的数列 (a)

    进行若干轮操作,每次操作在 ([1,N]) 中等概率选择一个使得 (a_i>0)(i),并将 (a_i) 减少 (1)

    问,期望多少次操作后 (a_1) 被减成了零。

    输入格式

    第一行一个整数 (N)

    第二行 (N) 个整数,第 (i) 个为 (a_i)

    输出格式

    一行一个整数,表示答案。为避免精度误差,答案对 323232323取模。

    即设答案化为最简分式后的形式为 (frac{a}{b}),其中 (a)(b) 互质。

    输出整数 (x) 使得 (bx≡a(mod323232323))(0≤x<323232323)

    可以证明这样的整数 (x) 是唯一的。

    input

    3
    
    2 3 3
    

    output

    202020207
    

    限制与约定

    题解

    算法 1

    答案可以看成是每一个元素被选中的次数之和。由于期望的线性性,我们可以去计算每一个位置被选中的次数的期望。

    首先,第一个元素一定被减了 (a_1) 次。

    考虑某一个位置 (i),假设当前有 (c) 个元素不为 (0),那么每个元素被操作的概率都是 (frac{1}{c})

    倘若只关注 (1)(i) 两个元素,可以发现操作其它元素的时候对它们没有影响,而且它们两个被操作的概率是相等的。

    于是这个问题就等价与一个只有两个元素的原问题。

    因此元素之间是独立的!使用算法 1 中的动态规划就可以知道每个元素对答案的贡献,求和即可。

    时间复杂度 (O(a^2+n))。期望得分 (60) 分。

    算法 2

    算法 3 中的动态规划可以看成从 ((a_1, a_i)) 出发的随机游走,每次随机一个方向将减 (1),直到走到坐标轴上为止。

    若停在 ((0,a)),对答案的贡献为 (a_i-a)。若停在 ((a,0)),对答案的贡献为 (a_i)

    于是可以直接写出贡献的式子。

    [sum_{i=0}^{a_i-1}i*frac{a_1-1+ichoose i}{2^{a_1+i}}+a_i(1-sum_{i=0}^{a_i-1}frac{a_1-1+ichoose i}{2^{a_1+i}}) ]

    前面那项是停留在 ((0,a)) 的答案,后面那项是停留在 ((a,0)) 的答案。

    (a_i) 增加 (1) 的时候,变化的贡献可以在 (O(1)) 的时间内得到。(前后都是只增加了一项)

    时间复杂度 (O(a+n))。期望得分 (100) 分。

    code

    #include<bits/stdc++.h>
    #define int long long
    #define re register int
    using namespace std;
    inline void read(int &x){
    	x=0;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar());
    	for(; isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    }
    const int N=1000010,i2=161616162,P=323232323;
    int n,m,s,p,a[N],fac[N],inv[N],f[N];
    inline int pw(int a,int b){
    	int res=1;
    	for(;b;b>>=1,a=a*a%P)
    		if(b&1)res=res*a%P;
    	return res;
    }
    inline int C(int a,int b){
    	return b<0||b>a?0:fac[a]*inv[b]%P*inv[a-b]%P;
    }
    signed main(){
    	read(n);
    	for(re i=1;i<=n;i++)read(a[i]),s+=a[i],s%=P;
    	for(re i=fac[0]=1;i<N;i++)fac[i]=fac[i-1]*i%P;
    	inv[N-1]=pw(fac[N-1],P-2);
    	for(re i=N-2;i>=0;i--)inv[i]=inv[i+1]*(i+1)%P;
    	f[1]=p=pw(2,P-1-a[1]);
    	for(re i=2;i<N/2;i++)
    		(p*=i2)%=P,f[i]=(f[i-1]*2-f[i-2]+C(a[1]+i-2,i-1)*p+P)%P;
    	for(re i=2;i<=n;i++)s+=P-f[a[i]],s%=P;
    	printf("%lld
    ",s);
    	return 0; 
    }
    
  • 相关阅读:
    狼羊过河问题
    java实现透明窗体
    商人胡萝卜问题
    NXP迅为IMX8开发板Andaoid编译环境搭建
    迅为龙芯2K1000开发板Linux下gcc编译
    迅为恩智浦i.MX8MM开发平台虚拟机安装Ubuntu16.04系统
    恩智浦NXP迅为i.MX6Q开发板资料提升了
    迅为龙芯2K1000开发板Linux工具之make工具和Makefile文件
    迅为瑞芯微3399开发板minimalYocto文件系统的构建
    迅为恩智浦IMX6Q开发板Buildroot 文件系统 alsa 声卡工具测试
  • 原文地址:https://www.cnblogs.com/Sparks-Pion/p/9656336.html
Copyright © 2020-2023  润新知