Gym - 102174
题意:
给定一个DAG,起点在
1
1
1号,经过每个节点会停留一天,之后第二天等概率的选择继续停留一天,或者走向后继节点。但每个节点最多停留两天,经过每条边会花费一天。走到不能走为止,求期望天数。
反向逆推答案,定义
d
p
[
i
]
dp[i]
dp[i]表示以
i
i
i号点为起点走到不能走为止的期望天数,
o
u
t
[
i
]
out[i]
out[i]表示第
i
i
i个点的出度。
初始化:
d
p
[
i
]
=
1
+
1
+
1
o
u
t
[
i
]
+
1
dp[i]=1+1+\frac{1}{out[i]+1}
dp[i]=1+1+out[i]+11 (到达第
i
i
i节点必定会在路上花费一天,到达后必定停留一天,又有
1
o
u
t
[
i
]
+
1
\frac{1}{out[i]+1}
out[i]+11的停留一天。注意当
i
=
1
i=1
i=1的时候,不必花费路上的一天,因为
1
1
1号点是起点)
转移:
d
p
[
i
]
+
=
∑
d
p
[
j
]
o
u
t
[
i
]
dp[i]+=\sum\frac{dp[j]}{out[i]}
dp[i]+=∑out[i]dp[j] 。由于花完初始化的天数后,会等可能地(
1
o
u
t
[
i
]
\frac{1}{out[i]}
out[i]1)选择其中一个后继节点并转移过来,所以每一个节点地期望为
d
p
[
j
]
o
u
t
[
i
]
\frac{dp[j]}{out[i]}
out[i]dp[j],再累和即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
#define inl inline
#define re register
#define MAXN 101000
const LL mod=998244353ll;
using namespace std;
int n,m;
struct edge
{
int to;
edge* next;
}head[101000],stac[MAXN<<1];
int ind;
edge& gets(){return stac[++ind];}
void add(int from,int to)
{
edge *p=&gets();
p->to=to;
p->next=head[from].next;
head[from].next=p;
}
LL dp[MAXN],du[MAXN];
LL qpow(LL a,LL b)
{
LL ans=1;
for(;b;b>>=1,a=a*a%mod)if(b&1)ans=a*ans%mod;
return ans;
}
bool vis[MAXN];
LL inv(LL i){return qpow(i,mod-2);}
void dfs(int i)
{
vis[i]=1;
dp[i]=(2+inv(du[i]+1))%mod;
if(i==1)dp[i]--,dp[i]%=mod;
for(edge *p=head[i].next;p!=NULL;p=p->next)
{
if(!vis[p->to])dfs(p->to);
dp[i]=(dp[i]+dp[p->to]*inv(du[i]))%mod;
}
}
int main()
{
int T;cin>>T;
while(T--)
{
ind=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)head[i].next=NULL,vis[i]=dp[i]=du[i]=0;
for(int s,v,i=1;i<=m;i++)
{
scanf("%d%d",&s,&v);
du[s]++;add(s,v);
}
dfs(1);
printf("%lld\n",(dp[1]%mod+mod)%mod);
}
return 0;
}