解法:拓扑排序 + DP

为终点的路径总数,由于题目说可以自己到自己,所以直接全部初始化为
计算公式:
为终点的所有路径的长度之和
计算公式:
其中 表示以 为终点长度为 的路径数量

显然在拓扑排序 的过程中:

对于 : 每条以 为终点的路径都可以加上 这一条边从而形成以 为终点的路径, 的贡献为 ,即
对于 : 显然 ,所以 的贡献为 ,即

因此只需要一边拓扑排序一边转移,最终答案=所有路径的长度/路径总数,即 /

注意:不能忽略重边的影响,也需要考虑!
(请自动忽略代码中的一些不良习惯和一大堆没用的火车头)

/*
* @Author: Phon
* @Date:   2024-10-10 22:42:14
* @Last Modified by:   Phon
* @Last Modified time: 2025-11-14 23:19:02
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long i64;
typedef unsigned long long u64;
typedef __int128_t i128;
typedef double db;
#define int long long
typedef pair<int, int> PII;
constexpr int MAXN = 3e3 + 100;
constexpr i64 INF = 1e18;
// constexpr int mod = 1e9 + 7;
constexpr i64 mod = 998244353;
// int mod;
// i64 Pow (i64 a, i64 k, i64 mod) {i64 ans=1;for(;k;k>>=1,a=1ll*a*a%mod)if(k&1)ans=1ll*ans*a%mod;return ans;}
i64 Pow (i64 a, i64 k, i64 mod) {i128 ans=1;for(;k;k>>=1,a=(i128)a*a%mod)if(k&1)ans=(i128)ans*a%mod;return (i64)ans;}
i64 inv (i64 x, i64 mod) {return Pow(x,mod - 2,mod);}
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};  // 下, 右, 上, 左
// int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};  // 上, 下, 左, 右

inline void pre_work(){    

}
using a4 = array<int, 4>;
using a3 = array<int, 3>;
using a2 = array<int, 2>;
 
int chmax(int &x, int y){
    if(x < y){
        x = y;
        return 1;
    }else return 0;
}
int chmin(int &x, int y){
    if(x > y){
        x = y;
        return 1;
    }else return 0;
}

template <typename _T>
inline void read(_T &f) {
    f = 0; _T fu = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') { fu = -1; } c = getchar(); }
    while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = getchar(); }
    f *= fu;
}
 
template <typename T>
void print(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x < 10) putchar(x + 48);
    else print(x / 10), putchar(x % 10 + 48);
}

inline void solve() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> edge(n + 1);
    vector<int> in(n + 1);
    for(int i = 0; i < m; i ++){
        int u, v;
        cin >> u >> v;
        edge[u].push_back(v), in[v] ++;
    }
    vector<int> f(n + 1, 1), g(n + 1);
    queue<int> q;
    for(int i = 1; i <= n; i ++){
        if(!in[i]) q.push(i);
    }
    while(!q.empty()){
        auto u = q.front(); 
        q.pop();
        for(auto v : edge[u]){
            f[v] = (f[v] + f[u]) % mod;
            g[v] = (g[v] + g[u] + f[u]) % mod;
            if(--in[v] == 0){ 
                q.push(v);
            }    
        }
    }
    int zi = 0, mu = 0;
    for(int i = 1; i <= n; i ++){
        zi = (zi + g[i]) % mod;
        mu = (mu + f[i]) % mod;
    }
    cout << zi * inv(mu, mod) % mod << '\n';
}  
/*

*/
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int T = 1; 
    // cin >> T;
    pre_work();
    while(T--)
        solve();    
    return 0;
}