Expectation

Expectation

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)

Problem Description

You are given an undirected graph consisting of n n n vertices with m m m weighted edges. We define the weight of a spanning tree as the bitwise AND of all edges’ weight in spanning tree.

Now select a spanning tree randomly, you should calculate the expected value of the weight of this spanning tree. You are required to print the result mod 998244353 998244353 998244353. i.e., print x y \frac{x}{y} yx mod 998244353 998244353 998244353 where x y \frac{x}{y} yx is the irreducible fraction representation of the result, where y − 1 y^{-1} y1 denotes the multiplicative inverse of y y y modulo 998244353 998244353 998244353.

Input

The first line is an integer t ( 1 ≤ t ≤ 10 ) t(1≤t≤10) t(1t10), the number of test cases.

For each test case, there are two space-separated integers n ( 2 ≤ n ≤ 100 ) n(2≤n≤100) n(2n100) and m ( 1 ≤ m ≤ 1 0 4 ) m(1≤m≤10^4) m(1m104) in the first line, the number of nodes and the number of edges.

Then follows m lines, each contains three integers u , v , w ( 1 ≤ u , v , ≤ n , 1 ≤ w ≤ 1 0 9 , u ≠ v ) u,v,w(1≤u,v,≤n,1≤w≤10^9,u≠v) u,v,w(1u,v,n,1w109,u=v), space separated, denoting an weight edge between u u u and v v v has weight w w w.

Output

For each test case, output a single line with a single integer, denoting the answer.

Sample Input

1
3 3 
1 2 1 
1 3 1
2 3 1

Sample Output

1

知识点

矩阵树
对于一个无向图 G ,它的生成树个数等于其基尔霍夫Kirchhoff矩阵任何一个N-1阶主子式的行列式的绝对值。
例:
Expectation_第1张图片

思路

题目要求每个生成树边权&&的期望值。
假设当前这颗生成树对二进制数的第 i i i位有贡献,则这个位上的构成生成树的边权值一定是 1 1 1,所以我们可以跑 31 31 31位二进制数的,矩阵树,每个位上的贡献度等于,这个位上的生成树数量乘以这个位上的 2 2 2次幂,最后再跑一边生成树计数,然后即可求得期望。

/***  Amber  ***/
#pragma GCC optimize(3,"Ofast","inline")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
typedef long long ll;
typedef pair<int,int> pii;
template <typename T>
inline void read(T &x) {
     
    x = 0;
    static int p;
    p = 1;
    static char c;
    c = getchar();
    while (!isdigit(c)) {
     
        if (c == '-')p = -1;
        c = getchar();
    }
    while (isdigit(c)) {
     
        x = (x << 1) + (x << 3) + (c - 48);
        c = getchar();
    }
    x *= p;
}
template <typename T>
inline void print(T x) {
     
    if (x<0) {
     
        x = -x;
        putchar('-');
    }
    static int cnt;
    static int a[50];
    cnt = 0;
    do {
     
        a[++cnt] = x % 10;
        x /= 10;
    } while (x);
    for (int i = cnt; i >= 1; i--)putchar(a[i] + '0');
    puts("");
}
const double Pi=acos(-1);
const double eps=1e-6;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const ll Inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 110;

int A[maxn][maxn],u[maxn * maxn],v[maxn * maxn],w[maxn * maxn];
int n,m;
inline void add(int u,int v,int w) {
     
    A[u][v] = (A[u][v] - w) % mod;
    A[v][v] = (A[v][v] + w) % mod;
}
ll qpow(ll a,ll b) {
     
    ll res = 1;
    while (b) {
     
        if (b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}
ll inv(ll x){
     
    return qpow(x,mod-2);
}
ll gauss(int n) {
     
    ll res = 1;
    for (int i = 1; i <= n; i++) {
     
        for (int j = i; j <= n; j++) {
     
            if (A[j][i]) {
     
                for (int k = i; k <= n; k++) swap(A[i][k], A[j][k]);
                if (i != j) res = -res;
                break;
            }
        }
        if (!A[i][i]) return 0;
        for (ll j = i + 1, iv = inv(A[i][i]); j <= n; j++) {
     
            ll t = A[j][i] * iv % mod;
            for (int k = i; k <= n; k++) {
     
                A[j][k] = (A[j][k] - t * A[i][k] % mod + mod) % mod;
            }
        }
        res = (res * A[i][i] % mod + mod) % mod;
    }
    return res;
}
inline void work() {
     
    read(n);
    read(m);
    for (int i = 1; i <= m; i++) {
     
        read(u[i]);
        read(v[i]);
        read(w[i]);
    }
    ll ans = 0;
    for (int i = 0; i < 32; i++) {
     
        memset(A, 0, sizeof(A));
        for (int j = 1; j <= m; j++) {
     
            add(u[j], v[j], w[j] >> i & 1);
            add(v[j], u[j], w[j] >> i & 1);
        }
        ans = (ans + gauss(n - 1) * (1 << i) % mod) % mod;
    }
    memset(A, 0, sizeof(A));
    for (int j = 1; j <= m; j++) {
     
        add(u[j], v[j], 1);
        add(v[j], u[j], 1);
    }
    ans = ans * inv(gauss(n - 1)) % mod;
    print(ans);
}
int main() {
     
    //freopen("1.txt","r",stdin);
    int T = 1;
    read(T);
    while (T--) {
     
        work();
    }
    return 0;
}


你可能感兴趣的:(图论,acm竞赛)