AT_abc277_g [ABC277G] Random Walk to Millionaire
ABC277G\(\mathbf{} \begin{Bmatrix} \frac{{\Large ABC277G} }{{\color{Red}\Large Solution} }\mathbf{} {No.32} \end{Bmatrix}\times{}\) NeeDna
题目描述
给定一个包含 \(N\) 个顶点和 \(M\) 条边的连通且简单的无向图。
对于 \(i = 1, 2, \ldots, M\),第 \(i\) 条边连接顶点 \(u_i\) 和顶点 \(v_i\)。
高桥君一开始处于顶点 \(1\),等级为 \(0\),然后他会恰好进行 \(K\) 次如下操作:
- 首先,从当前所在顶点的所有相邻顶点中,等概率随机选择一个顶点并移动到该顶点。
- 然后,根据移动后的顶点 \(v\),会发生如下事件:
- 如果 \(C_v = 0\):高桥君的等级增加 \(1\)。
- 如果 \(C_v = 1\):设高桥君当前等级为 \(X\),他会获得 \(X^2\) 日元。
请输出在上述 \(K\) 次操作过程中,高桥君获得的金钱总额的期望值,结果对 \(998244353\) 取模。
题解
这是一道期望dp,我们观察一下数据范围,这题是 \(\Theta(nk)\) 的,我们可以干什么呢,可以遍历 \(k\) 次图!
- 我们会算第 \(i\) 步到达的等级期望 \(q_{i,u}=[(vis_u=1)\wedge (c_u=0)]+\sum^{}_{u\to v} q_{i-1,v}\times d_v^{-1}\).
- 这题的这个平方不是可以直接算的,你考虑当前的期望等级相当于包含转移到它的许多状态,直接开方,这些状态会两两相乘,这是错的。所以需要算期望“等级的平方值”(注意我的断句)。
- 我们发现 \((x+1)^2 = x^2+2\times x+1\) 这下我们就没有直接算 \((x+1)^2\) 了,而 \(x\) 是有线性可加性的,所以答案是对的。
- 所以我们就会算第 \(i\) 步到达的期望等级的平方值 \(E_{i,u}=[(vis_u=1)\wedge (c_u=0)]\times(2\times q_{i,u}-1)+\sum^{}_{u\to v} E_{i-1,v}\times d_v^{-1}\).
最后把 \(c_i=1\) 的答案累加即可。
细节
代码里 \(f_{k,u,0}\) 代表了 \([(vis_u=1)]\)。
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e3+10,mod=998244353;
int n,m,k,f[N][N][3],inv[N],c[N],d[N],ans;
vector<int>g[N];
int ksm(int x,int k){
int ans=1;
while(k>1){
if(k%2) ans=ans*x%mod;
x=x*x%mod;k/=2;
}return ans*x%mod;
}
signed main(){
cin>>n>>m>>k;
for(int i=1,u,v;i<=m;i++){
cin>>u>>v;d[u]++,d[v]++;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++) inv[i]=ksm(d[i],mod-2);
for(int i=1;i<=n;i++) cin>>c[i];
f[0][1][0]=1;
for(int i=1;i<=k;i++){
for(int u=1;u<=n;u++){
for(int v:g[u]){
f[i][u][0]=(f[i-1][v][0]*inv[v]+f[i][u][0])%mod;
f[i][u][1]=(f[i-1][v][1]*inv[v]+f[i][u][1])%mod;
f[i][u][2]=(f[i-1][v][2]*inv[v]+f[i][u][2])%mod;
}
if(c[u])ans=(ans+f[i][u][2])%mod;
else{
f[i][u][1]+=f[i][u][0];
f[i][u][2]=(f[i][u][2]+2*f[i][u][1]-f[i][u][0])%mod;
}
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号