L. 旅行的意义
time limit per test
1.0 s
memory limit per test
256 MB
input
standard input
output
standard output
为什么有人永远渴望旅行,或许就因为,巧合和温暖会在下一秒蜂拥而至吧。
一直想去旅游的天天决定在即将到来的五一假期中安排一场环游世界的旅行。为此,他已经提前查阅了很多资料,并准备画一张旅游路线图。天天先将所有可能会去的 nn 个旅游城市依次编号标记为 1,2,⋯,n1,2,⋯,n。如果从城市 AA 到城市 BB 有一条直达的铁路线路,他就会在图上画上一条从 AA 向 BB 的有向线段。因为天天不喜欢把时间浪费在往返的乘车上,因此他设计的旅游地图路线是一个有向无环图。
天天身在 11 号城市,他每到达一个旅游城市都会先花一天的时间游玩当地的旅游景点。接下来他也没有明确的目的地,所以第二天他会随机地选择该城市的一条直达线路,花费一天的时间通往下一个旅游城市。当然,如果这个城市的旅游景点太好玩的话,他可能会选择再逗留一天,但是由于假期有限,他在当前的旅游城市最多只能呆 22 天。例如,当天天在城市 CC 时,若城市 CC 有 22 条直达线路分别通往城市 AA 和城市 BB,则在第一天的游玩过后,第二天他有 1313 的可能会选择继续逗留在城市 CC 多游玩一天,但是第三天他一定不会再逗留在城市 CC 了;同时他有 1313 可能会选择立即搭乘直达城市 AA 的高铁;他也有 1313 的可能会选择立即搭乘直达城市 BB 的高铁。
当天天把所有的旅游城市都游玩过后,他也就只能结束这段难忘的五一旅行假期了。现在请聪明的你帮天天提前计算一下,他本次旅行时间的期望是多少呢?
容易证明天天旅行时间的期望为 PQPQ 的形式,其中 PP 和 QQ 互质,且 Q≢0 (mod 998244353)Q≢0 (mod 998244353)。因此答案请以 P⋅Q−1 (mod 998244353)P⋅Q−1 (mod 998244353) 的形式输出,其中 Q−1Q−1 表示 QQ 在取模 998244353998244353 下的逆元。
Input
第一行输入一个正整数 T (1≤T≤10)T (1≤T≤10),表示数据组数。接下来 TT 组数据,每组数据均满足:
- 第一行输入两个非负整数 n (1≤n≤105)n (1≤n≤105) 和 m (0≤m≤105)m (0≤m≤105),分别表示天天可能旅行的城市数量 nn 和它们之间的直达线路数量 mm。
- 接下来 mm 行,每行输入两个正整数 uu 和 v (1≤u,v≤n)v (1≤u,v≤n),表示从城市 uu 到 vv 有一条单向直达线路,保证两个旅游城市之间最多只有 11 条直达线路。
Output
对于每组数据,请输出一个非负整数,表示天天旅行时间的期望,注意换行。
Example
input
Copy
2
1 0
2 1
1 2
output
Copy
2
499122181
Note
第一组样例只有一个旅游城市。首先,天天会在该城市游玩一天,第二天只剩下一个选择——留下来接着玩一天,再之后他就只能结束旅程了,所以旅游时间的期望是 22。
第二组样例由两个旅游城市,从城市 11 到城市 22 有一条直达的线路。天天首先在城市 11 游玩一天,然后有 1212 的概率前往城市 22,这将花费 11 天时间乘坐高铁;当然天天也有 1212 的概率逗留在城市 11 多玩一天,第三天再乘坐高铁前往城市 22。因此刚到达城市 22 时,天天花费的旅行时间期望是 1+[12⋅1+12⋅(1+1)]=2.51+[12⋅1+12⋅(1+1)]=2.5 天。接着天天会在城市 22 先游玩一天,但是接下来他没有其他城市可以去了,只能选择继续逗留一天然后终止旅程,容易算出本次旅程总的时间期望为 4.54.5 天,即 92=9⋅2−1 (mod 998244353)=49912218192=9⋅2−1 (mod 998244353)=499122181。
抓住重点:每次到达一个城市一定是先玩一天,第二天有几率再玩一天,第三天必须得走。走向下一个城市得时候会发费一天得时间坐高铁。
设dp[u]代表着从u结点出发时的游玩天数的期望。部分题解写在代码里了。
涉及了回溯的过程
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int N=1e5+10;
vector<int>G[N];//存图
ll dp[N];
ll powmod(ll a,ll b){
ll res=1;
a%=mod;
for(; b;b>>=1){
if(b&1) res=res*a%mod;
a=a*a%mod;
}
return res%mod;
}
ll inv(ll x){
return powmod(x,mod-2);
}
void dfs(int u){
ll len=G[u].size();
if(u==1) dp[1]=1+inv(len+1);//从一城市开始,必先玩一天1
//第二天有1/(len+1)的概率再玩一天::1+1/(len+1)
else dp[u]=2+inv(len+1);//坐高铁花一天和到达一个城市先玩一天,
//第二天有1/(len+1)的概率再玩一天
for(auto v:G[u]){
if(dp[v]){
dp[u]=(dp[u]+dp[v]*inv(len)%mod)%mod;//有1/(len)的概率去这个儿子结点
}
else{
dfs(v);
dp[u]=(dp[u]+dp[v]*inv(len)%mod)%mod;
}
}
}
int main(){
int t;
cin>>t;
while(t--){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) G[i].clear(),dp[i]=0;
for(int i=1;i<=m;++i){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
dfs(1);
printf("%lld\n",dp[1]%mod);
}
}