Solution S o l u t i o n
因为这是一张竞赛图,所以把强连通分量缩起来以后回事一条链的情况。
那么强连通分量的数量就是相当于缩起来以后的点的数量。
对于图
G(V,E)
G
(
V
,
E
)
来说,这样的点集
S⊆V
S
⊆
V
,满足两个点集的边是这样的关系
e∈E^={(u,v)|u∈S,v∈V−S}
e
∈
E
^
=
{
(
u
,
v
)
|
u
∈
S
,
v
∈
V
−
S
}
。
考虑
m
m
条特殊的边对答案的贡献。原来点集 的贡献是
12|S|(n−|S|)
1
2
|
S
|
(
n
−
|
S
|
)
。那么现在一条特殊的边相当于有
2p
2
p
的贡献。
就只需要考虑
m
m
条边的情况,计算出强连通分量大小 后乘上
12x(n−x)
1
2
x
(
n
−
x
)
就好了。
可以每个联通块里枚举哪些点
u∈S
u
∈
S
,把这些边的贡献记录下来,背包起来就好了。
#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
const int N = 50;
const int INV = 796898467;
typedef long long ll;
vector<int> G[N];
vector<int> cc;
int n, m, x, y, z, gcnt, clc;
int vis[N], head[N], id[N];
int from[N], to[N], key[N];
int sum[N][N], dp[N][N];
inline void add(int &x, int a) {
x = (x + a >= MOD) ? x + a - MOD : x + a;
}
inline int pwr(int a, int b) {
b = (b % (MOD - 1) + MOD - 1) % (MOD - 1);
int c = 1;
while (b) {
if (b & 1) c = (ll)c * a % MOD;
b >>= 1; a = (ll)a * a % MOD;
}
return c;
}
inline void addEdge(int from, int to) {
G[from].emplace_back(to);
G[to].emplace_back(from);
}
inline void dfs(int u) {
vis[u] = clc;
id[u] = cc.size();
cc.emplace_back(u);
for (int to: G[u])
if (!vis[to]) dfs(to);
}
int main(void) {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> x >> y >> z;
z = (ll)z * INV % MOD;
addEdge(x, y);
from[i] = x;
to[i] = y;
key[i] = z;
}
for (int i = 1; i <= n; i++)
if (!vis[i]) {
cc.clear();
++clc; dfs(i);
for (int s = 0; s < (1 << cc.size()); s++) {
int res = 1;
for (int i = 1; i <= m; i++) {
int u = from[i], v = to[i];
if (vis[u] != clc) continue;
if ((s >> id[u] & 1) == (s >> id[v] & 1)) continue;
if (s >> id[u] & 1) res = 2ll * res * key[i] % MOD;
else res = 2ll * res * (MOD + 1 - key[i]) % MOD;
}
add(sum[clc][__builtin_popcount(s)], res);
}
}
dp[0][0] = 1;
for (int i = 0; i < clc; i++)
for (int j = 0; j < n; j++)
if (dp[i][j])
for (int k = 0; k + j < n; k++)
add(dp[i + 1][k + j], (ll)dp[i][j] * sum[i + 1][k] % MOD);
int ans = 0;
for (int i = 0; i <= n; i++)
add(ans, (ll)dp[clc][i] * pwr(2, -i * (n - i)) % MOD);
ans = (ll)ans * pwr(10000, n * n - n) % MOD;
cout << ans << endl;
return 0;
}