2020杭电多校第六场 Expectation(期望,基尔霍夫矩阵)

Problem Description
You are given an undirected graph consisting of n vertices with 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. i.e., print x×y−1 mod 998244353 where x×y−1 is the irreducible fraction representation of the result, where y−1 denotes the multiplicative inverse of y modulo 998244353.

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

For each test case, there are two space-separated integers n(2≤n≤100) and m(1≤m≤104) 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≤109,u≠v), space separated, denoting an weight edge between u and v has weight 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

题意:
一个图,生成树的权值为其边权按位与和。求生成树权值期望。

思路:
基尔霍夫矩阵可以求出生成树个数。

我们按照每个二进制位考虑,假设对于第 i i i个二进制位,肯定要全部边这个二进制位均为1才有贡献,所以把这个二进制位为0的边全删了重新建图,再乘以此时的生成树个数就可以得到这个二进制位的贡献。

#include 
#include 
#include 

using namespace std;
typedef long long ll;
const int maxn = 1e4 + 7;
const int mod = 998244353;

int degree[105];
ll a[105][105];
int vis[105][105];

struct Edge {
    int x,y,z;
}edges[maxn];

void init(){
    memset(degree,0,sizeof(degree));
    memset(a,0,sizeof(a));
    memset(vis,0,sizeof(vis));
}

ll qpow(ll x,ll n) {
    ll res = 1;
    while(n) {
        if(n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res % mod;
}

ll det(int n){
    ll ret=1;
    for(int i=2;i<=n;i++){
        for(int j = i + 1;j <= n;j++) {
            a[i][j] %= mod;
        }
        for(int j=i+1;j<=n;j++){
            while(a[j][i]){
                ll t=a[i][i]/a[j][i];
                for(int k=i;k<=n;k++){
                    a[i][k]=(a[i][k]-a[j][k]*t) % mod;
                }
                for(int k=i;k<=n;k++){
                    swap(a[i][k],a[j][k]);
                }
                ret=-ret;
            }
        }
        if( a[i][i]==0 ) return 0;
        ret*=a[i][i];
        ret %= mod;
    }
    ret = (ret % mod + mod) % mod;
    return ret % mod;
}

int main() {
    int t;
    scanf("%d",&t);
    while( t-- ) {
        init();
        int n,m;scanf("%d%d",&n,&m);
        for(int i = 1;i <= m;i++) {
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            edges[i] = {x,y,z};
            a[x][x]++;
            a[y][y]++;
            a[x][y]--;
            a[y][x]--;
        }
        
        ll ans = 0,sum = 0;
        sum = det(n) % mod;
        for(int i = 0;i <= 30;i++) {
            init();
            for(int j = 1;j <= m;j++) {
                int u = edges[j].x,v = edges[j].y;
                if((edges[j].z >> i) & 1) {
                    a[u][u]++;
                    a[v][v]++;
                    a[u][v]--;
                    a[v][u]--;
                }
            }
            ll num = det(n) % mod;
            ans = (ans + num * (1 << i) % mod) % mod;
        }
//        printf("%lld %lld\n",ans,sum);
        ans = ans * qpow(sum,mod - 2) % mod;
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(#,其他比赛题目,#,基尔霍夫矩阵,#,概率)