Skip to main content
Original460 words2 min

题解:P14514 [NFLSPC #8] 如何区分北京东路和北京东路

Summary

给定长度 n 的数列,每次随机选一个元素清零并把它平均分给其他 n 减 1 个元素,求 k 次操作后每个位置的期望,对 998244353 取模。数列总和恒为定值。对单个位置写出一步期望,化简成关于上一步的线性递推,系数为 (n-2)/(n-1),常数项含总和,再套等比数列求和得到通项公式,用快速幂和逆元计算。时间复杂度 O(nlogk)。

题意简述​

给定长度为 nn 的数列 aia_i,每次随机选择 11 个元素平均分给其他 n−1n-1 个元素,求 kk 次操作后 aia_i 的期望。

解题思路​

数列 aia_i 的总和始终为定值 ss:

s=∑i=1nais=\sum_{i=1}^n a_i

设 j∈[0,k]j\in[0,k] 次操作后 aia_i 的期望为 ai,ja_{i,j}。特别地,ai,0=aia_{i,0}=a_i。

如果 jj 次操作选择了 p∈[1,n]p\in[1,n],则有:

ai,j={0p=iai,j−1+ap,j−1n−1p≠ia_{i,j}= \begin{cases} 0 & p=i \\ a_{i,j-1}+\frac{a_{p,j-1}}{n-1} & p\ne i \end{cases}

因此 ai,ja_{i,j} 的期望为:

ai,j=∑p=1,p≠in1n(ai,j−1+ap,j−1n−1)=n−1n⋅ai,j−1+1n(n−1)∑p=1,p≠inap,j−1=n−1n⋅ai,j−1+s−ai,j−1n(n−1)=n−1n⋅ai,j−1+sn(n−1)−1n(n−1)⋅ai,j−1=(n−1)2−1n(n−1)⋅ai,j−1+sn(n−1)=n−2n−1⋅ai,j−1+sn(n−1)\begin{aligned} a_{i,j} & =\sum_{p=1,p\ne i}^n\frac{1}{n}\left(a_{i,j-1}+\frac{a_{p,j-1}}{n-1}\right) \\ & =\frac{n-1}{n}\cdot a_{i,j-1}+\frac{1}{n(n-1)}\sum_{p=1,p\ne i}^n a_{p,j-1} \\ & =\frac{n-1}{n}\cdot a_{i,j-1}+\frac{s-a_{i,j-1}}{n(n-1)} \\ & =\frac{n-1}{n}\cdot a_{i,j-1}+\frac{s}{n(n-1)}-\frac{1}{n(n-1)}\cdot a_{i,j-1} \\ & =\frac{(n-1)^2-1}{n(n-1)}\cdot a_{i,j-1}+\frac{s}{n(n-1)} \\ & =\frac{n-2}{n-1}\cdot a_{i,j-1}+\frac{s}{n(n-1)} \end{aligned}

显然 ai,ja_{i,j} 的值只与 ai,j−1a_{i,j-1} 有关,这是一个线性递推。设:

x=n−2n−1,y=sn(n−1)x=\frac{n-2}{n-1},y=\frac{s}{n(n-1)}

得到 ai,ka_{i,k} 的通项公式:

ai,k=xkai,0+y(xk−1+xk−2+⋯+x+1)=xkai,0+y⋅xk−1x−1\begin{aligned} a_{i,k} & =x^ka_{i,0}+y\left(x^{k-1}+x^{k-2}+\dots+x+1\right) \\ & =x^k a_{i,0}+y\cdot\frac{x^k-1}{x-1} \end{aligned}

参考代码​

593 Bcpp
#include <bits/stdc++.h>
using namespace std;

using ll=long long;
const int mod=998244353;
const int N=1000005;
ll a[N];
ll Pow(ll x,ll y)
{
x%=mod;
ll res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,k;
cin>>n>>k;
ll sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum=(sum+a[i])%mod;
}
ll x=(n-2)*Pow(n-1,mod-2)%mod,y=sum*Pow(n,mod-2)%mod*Pow(n-1,mod-2)%mod;
for(int i=1;i<=n;i++)
{
cout<<(Pow(x,k)*a[i]%mod+y*(Pow(x,k)-1)%mod*Pow(x+mod-1,mod-2)%mod)%mod<<' ';
}
return 0;
}