[ABC310G]Takahashi And Pass-The-Ball Game
题目链接
题目大意
有\(n\)个人,第\(i\)个人有一个目标\(a_i\),和拥有的球的数量\(b_i\)
对于随机的\(x\in\left[1,k\right]\),进行x次以下操作:
- 第\(i\)个人将自己手中所有的球交给第\(a_i\)个人(所有人同时进行)
求出第\(i\)个人在结束时手里球的个数的期望
对998244353取模
解决方法
容易发现第\(i\)个人在结束时手里球的个数的期望就是对于每个\(x\in\left[1,k\right]\)的第\(i\)个人手里球的个数和除以\(k\)
首先处理除以\(k\)
因为要对998244353取模,所以除以\(k\)就是乘上\(k\)的逆元,用快速幂求即可
然后很容易想到一个暴力做法:
对于第\(i\)个人,枚举他手中的球传递了几次,每次传递后这个人手里球的个数和加上第\(i\)个人手中的球,最后统一除以\(k\)
for(int i=1;i<=n;i++) {
int now=i;
for(int j=1;j<=k;j++) {
now=a[now];
ans[now]=(ans[now]+b[i])%mod;
}
}
for(int i=1;i<=n;i++) {
cout<<ans[i]*invk%mod<<" ";
}
时间复杂度为\(O(nk)\),显然超时
刚才是先枚举第几个人的球,我们还可以先枚举传递了几次
具体来说,就是枚举\(j\),用\(nowa_i\)表示第\(i\)个人手里的球传递了\(j\)次后在谁手上
vector<int>nowa=a;
for(int j=1;j<=k;j++) {
for(int i=1;i<=n;i++) {
ans[nowa[i]]=(ans[nowa[i]]+b[i])%mod;
}
vector<int>nxtnowa(n+1);
for(int i=1;i<=n;i++) {
nxtnowa[i]=a[nowa[i]];
}
nowa=nxtnowa;
}
for(int i=1;i<=n;i++) {
cout<<ans[i]*invk%mod<<" ";
}
时间复杂度仍然为\(O(nk)\)
由于时间主要是\(k\)太大(\(10^{18}\)),可以将其优化为\(O(log_2k)\)的
具体来说是这样的:
我们有\(nowa_i\)表示第\(i\)个人手里的球传递了\(j\)次后在谁手上,我们可以这么改一下定义:
\(nowa_i\)表示第\(i\)个人手里的球传递了\(2^j\)次后在谁手上
初始:
vector<int>nowa=a;
转移:
vector<int>nxtnowa(n+1);
for(int i=1;i<=n;i++) {
nxtnowa[i]=nowa[nowa[i]];
}
nowa=nxtnowa;
此时仍然套用以上思路,但是直接使用\(b_i\)肯定是不行的,因为\(b_i\)表示传递一次会贡献多少球,需要用\(nowb_i\)表示传递\(2^j\)次会给第\(i\)个人贡献多少球
初始:
vector<int>nowb(n+1);
for(int i=1;i<=n;i++) {
nowb[a[i]]=(nowb[a[i]]+b[i])%mod;
}
转移:
vector<int>nxtnowb(n+1);
for(int i=1;i<=n;i++) {
nxtnowb[nowa[i]]=(nxtnowb[nowa[i]]+nowb[i])%mod;
}
for(int i=1;i<=n;i++) {
nowb[i]=(nowb[i]+nxtnowb[i])%mod;
}
那么就可以用一个类似于快速幂的东西将其优化为\(O(log_2k)\)
vector<int>nowa=a;
vector<int>nowb(n+1);
for(int i=1;i<=n;i++) {
nowb[a[i]]=(nowb[a[i]]+b[i])%mod;
}
while(k>0) {
if(k&1) {
for(int i=1;i<=n;i++) {
ans[i]=(ans[i]+nowb[i])%mod;
}
vector<int>nxtnowb(n+1);
for(int i=1;i<=n;i++) {
nxtnowb[nowa[i]]=(nxtnowb[nowa[i]]+nowb[i])%mod;
}
nowb=nxtnowb;
}
vector<int>nxtnowb(n+1);
for(int i=1;i<=n;i++) {
nxtnowb[nowa[i]]=(nxtnowb[nowa[i]]+nowb[i])%mod;
}
for(int i=1;i<=n;i++) {
nowb[i]=(nowb[i]+nxtnowb[i])%mod;
}
vector<int>nxtnowa(n+1);
for(int i=1;i<=n;i++) {
nxtnowa[i]=nowa[nowa[i]];
}
nowa=nxtnowa;
k>>=1;
}
for(int i=1;i<=n;i++) {
cout<<ans[i]*invk%mod<<" ";
}
于是我们就能在\(O(nlog_2k)\)的时间内求解
浙公网安备 33010602011771号