取球游戏 解题报告

题目描述

有一个长度为 \(n\) 的数组,初始给定数组的所有值,并给出所有值的和 \(m\)

每一次带权选择一个下标( \(i\)\(\frac{a_i}{m}\) 的概率被选中),执行 \(a_i \leftarrow a_i-1,a_{i+1} \leftarrow a_{i+1}+1\)。特别地,当 \(i=n\) 时,执行 \(a_n \leftarrow a_n-1,a_1 \leftarrow a_1+1\)

询问 \(k\) 次操作后数组中每一个位置的期望值。

数据范围:\(n \le 10^3,m \le 10^7,k \le 2^{31}-1\)

分析

简单模拟就可以发现:

\[\begin{aligned} a_i &=a_i+\frac{a_{i-1}}{m}-\frac{a_i}{m} \\ &=\frac{1}{m}a_{i-1}+\frac{m-1}{m}a_i \end{aligned} \]

然后我们关注系数。可以发现这是一个生成函数的形式,生成函数为 \(F=(\frac{m-1}{m}x+\frac{1}{m})^k\)。第 \(i-p\) 项的系数等于 \(\sum \limits_{j \equiv 0 \pmod n} F[i]\)。因为下标始终在模 \(n\) 意义下,因此在多项式乘法时可以将 \(i\) 的系数累加到 \(i \bmod n\) 上。

使用快速幂,时间复杂度 \(O(n^2logk)\)

代码

const int N=2e5+100;
int n,m,k,a[N];
double mx,p1[N],p2[N],p3[N];
void mul(double *v1,double *v2){
    For(i,0,n-1) p3[i]=0;
    For(i,0,n-1)
        For(j,0,n-1)
            p3[(i+j)%n]+=v1[i]*v2[j];
    For(i,0,n-1) v1[i]=p3[i];
}
void qpow(){
    while(k){
        if(k&1)
            mul(p2,p1);
        mul(p1,p1);
        k>>=1;
    }    
}
int main()
{
    freopen("ball.in","r",stdin);
    freopen("ball.out","w",stdout);
    n=read(),m=read(),k=read();
    For(i,1,n) a[i]=read();
    p1[0]=1.0*(m-1)/m,p1[1]=1.0/m;
    p2[0]=1;
    qpow();
    For(i,1,n){
        double res=0;
        For(j,0,n-1){
            int v=(i-j+n-1)%n+1;
            res+=a[v]*p2[j];
        }
        printf("%0.3lf\n",res);
    }
    return 0;
}
posted @ 2025-08-19 23:25  XiaoZi_qwq  阅读(11)  评论(0)    收藏  举报