给定一个有向无环图,
个点,
条边,可以存在重边。设
为图中所有简单路径(允许长度为
,即起点与终点相同)的集合。
从集合
中等概率随机选择一条路径并沿着它行走,定义一条路径的长度为其经过的边数
即随机变量
为所选路径的长度,计算
的期望值对
取模的结果,即%20%5C%20mod%5C%20998244353)
显然是离散型随机变量:
的取值可以为
,设对应的路径条数为
那么
所以现在就是求每个长度的路径的条数:
因为每个点都可以作为起点,如果从每个点
一遍的话,时间复杂度为
,一定超时的!
所以用到了拓扑排序+
的方法:
定义
表示以节点
为终点的全部路径条数;当
时,
定义
表示以节点
为终点的全部路径的长度;当
时,
详细解释:
-
,从
到
新增加了一条边,这一条边可以和以
为终点的所有路径构成新的路径,那么新增加了
条路径
-
,从
到
新增加了一条边,这一条边可以和以
为终点的所有路径构成新的路径,原来
条路径的长度为
,现在每条路径新增加了长度
,所以在
的基础上增加了长度为
,所以一共增加了
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 1e5 + 10;
const int mod = 998244353;
int n, m;
vector<int> adj[N];
int deg[N];
int f[N], g[N];
int ksm(int a, int b, int p){
a %= p;
int sum = 1;
while(b){
if(b & 1) sum = (sum * a) % mod;
b >>= 1;
a = (a * a) % mod;
}
return sum;
}
int gcd(int a, int b){
if(!b) return a;
else return gcd(b, a % b);
}
signed main(){
HelloWorld;
cin >> n >> m;
for(int i = 1; i <= m; i ++){
int u, v; cin >> u >> v;
adj[u].push_back(v);
deg[v] ++;
}
for(int i = 1; i <= n; i ++) f[i] = 1;
queue<int> q;
for(int i = 1; i <= n; i ++){
if(!deg[i]) q.push(i);
}
while(q.size()){
int u = q.front();
q.pop();
for(int v : adj[u]){
if(-- deg[v] == 0) q.push(v);
f[v] = (f[v] + f[u]) % mod;
g[v] = (g[v] + f[u] + g[u]) % mod;
}
}
int fz = 0, fm = 0;
for(int i = 0; i <= n; i ++){
fz = (fz + g[i]) % mod;
fm = (fm + f[i]) % mod;
}
int g = gcd(fz, fm);
fz /= g, fm /= g;
cout << (fz * ksm(fm, mod - 2, mod)) % mod;
return 0;
}



京公网安备 11010502036488号