游走(luogu)(期望)

题目地址
配套地址
在这里插入图片描述

答案为 s u m c n t \frac{sum}{cnt} cntsum sum 为所有路径的总长度,cnt为所有路径的个数。

题中信息可以得到,改图形是一个DAG,可以设f(i)表示以i为起点的所有路径的总长度之和,g(i)表示以i为起点的所有路径的个数。

那么 f ( i ) = ∑ j ∈ s ( f ( j ) + g ( j ) ) f(i) = \sum_{j\in{s}}(f(j) + g(j)) f(i)=js(f(j)+g(j))
首先边长为1,对于f(j)中的所有路径,当变成由i为起点时,每个路径都要加1的长度。所以要额外增加g(i)的长度。
g ( i ) = 1 + ∑ j ∈ s g ( j ) g(i) = 1 + \sum_{j\in{s}}g(j) g(i)=1+jsg(j),
1是自己到自己的路径。

那么 s u m = ∑ i = 1 n f ( i ) , c n t = ∑ i = 1 n g ( i ) sum = \sum_{i=1}^{n}f(i),cnt = \sum_{i=1}^{n}g(i) sum=i=1nf(i),cnt=i=1ng(i)

转移可以建立反图,跑拓扑序。

最后对答案求逆元就行了。

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;

int ne[N],e[N],h[N],idx=1;
int d[N],g[N],f[N];
int n,m;

void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void top_sort(){
	queue<int> qe;
	for(int i=1;i<=n;i++) if(!d[i]) qe.push(i);
	while(!qe.empty()){
		int t = qe.front();qe.pop();
		g[t] ++;
		for(int i=h[t];i;i=ne[i]){
			int j = e[i];
			g[j] = (g[t] + g[j]) % mod;
			f[j] = (f[j] + f[t] + g[t]) % mod;
			if(-- d[j] == 0) qe.push(j);
		}
	}
}

int qmi(int a,int b){
	int res = 1;
	while(b){
		if(b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}

signed main(){
	IOS
    cin>>n>>m;
	for(int i=1;i<=m;i++){
		int a,b; cin>>a>>b;
		add(b,a);
		d[a] ++;
	}
    top_sort();
    int up = 0,down = 0;
    for(int i=1;i<=n;i++) up = (up + f[i]) % mod;
    for(int i=1;i<=n;i++) down = (down + g[i]) % mod;
    int ans = up * qmi(down,mod-2) % mod;
    cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值