取球游戏 解题报告
题目描述
有一个长度为 \(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;
}

浙公网安备 33010602011771号