Solution
此题本人NFLSPC正赛场切。
让我们先一步步分析这个问题。
有
n 个城市,初始第
i 个城市的炸弹威力为
ai。
进行
k 次爆炸,每次随机选择一个城市(等概率
1/n)。
- 该城市的 危险度 为 当前炸弹威力 ax。
- 爆炸后,该城市的炸弹威力 清零(ax→0)。
- 其它每个城市 j=x 的炸弹威力 增加 ax/(n−1)(保持总威力不变)。
注意:这里“增加
ax/(n−1)” 是精确的数学关系,因为
ax 被均分给其它
n−1 个城市。
问题转化
设
Ei(t) 表示第
t 次爆炸后,城市
i 的炸弹威力的期望值。
初始:
Ei(0)=ai。
- 若 i=x:ai→0。
- 若 i=x:ai→ai+n−1ax。
推导递推式
考虑一次随机爆炸(每个城市概率
1/n)对
Ei(t+1) 的影响。
情况 1:爆炸发生在城市 i(概率 1/n)
- 爆炸后 Ei(t+1)=0。
情况 2:爆炸发生在城市 j=i(概率 nn−1 中的某一个 j)
- 对于固定的 j,概率 1/n,爆炸后:
Ei(t+1)=Ei(t)+n−1Ej(t)
注意这里 Ej(t) 是爆炸前 j 的期望威力。
情况 3:爆炸发生在其它城市 p(p=i 且 p=j 的情况已经包含在情况 2 的求和里)
所以:
Ei(t+1)=n1⋅0+j=i∑n1[Ei(t)+n−1Ej(t)]。
化简递推式
Ei(t+1)=j=i∑n1Ei(t)+j=i∑n1⋅n−1Ej(t)。
第一项:
∑j=in1Ei(t)=nn−1Ei(t)。
第二项:
∑j=in(n−1)Ej(t)。
注意
∑j=iEj(t)=S(t)−Ei(t),其中
S(t)=∑j=1nEj(t)。
所以:
Ei(t+1)=nn−1Ei(t)+n(n−1)S(t)−Ei(t)。
对 S(t) 的递推
总威力守恒:每次爆炸只是把
ax 从城市
x 均分给其它
n−1 个城市,所以总威力不变:
S(t)=i=1∑nai=S。
因此
S(t)=S 对所有
t 成立。
代入化简
Ei(t+1)=nn−1Ei(t)+n(n−1)S−Ei(t)。
合并
Ei(t) 的系数:
Ei(t+1)=[nn−1−n(n−1)1]Ei(t)+n(n−1)S
计算系数:
nn−1−n(n−1)1=n(n−1)(n−1)2−1=n(n−1)n2−2n+1−1=n(n−1)n(n−2)=n−1n−2
所以:
Ei(t+1)=n−1n−2Ei(t)+n(n−1)S
解递推式
这是一个一阶线性递推:
Ei(t)−C=n−1n−2(Ei(t−1)−C),
其中
C 是稳态值,令
E=n−1n−2E+n(n−1)S 解得:
E−n−1n−2E=n(n−1)S,
n−1E=n(n−1)S,
E=nS.
所以稳态时每个城市期望威力相同,等于平均值。
因此:
Ei(t)−nS=(n−1n−2)t(ai−nS)
即:
Ei(k)=nS+(n−1n−2)k(ai−nS)
模运算实现
要求取模
998244353,需要快速幂求
(n−1n−2)kmodM,以及乘逆元。
记为:
coef=(n−1n−2)k=(n−2)k⋅(n−1)−k(modM)。
平均值
avg=S⋅n−1(modM)。
则:
Ei(k)=avg+coef⋅(ai−avg)(modM)。
时间复杂度
快速幂:
O(logk)。
总和:
O(n+logk)。
AC code
CPP#include<bits/stdc++.h>
using namespace std;
const int M=998244353;
long long modpow(long long a,long long b)
{
long long r=1;
while(b)
{
if(b&1) r=r*a%M;
a=a*a%M;
b/=2;
}
return r;
}
int n,k,a[1000003];
int main()
{
cin>>n>>k;
long long s=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s=(s+a[i])%M;
}
long long inv_n=modpow(n,M-2),avg=s*inv_n%M,p=n-2,q=n-1,coef=modpow(p,k)*modpow(modpow(q,k),M-2)%M;
for(int i=1;i<=n;i++)
{
long long res=(avg+coef*(a[i]-avg+M))%M;
cout<<res<<" ";
}
return 0;
}