Expectation(生成树计数)

题目描述
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.

输入
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.

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

样例输入
1
3 3
1 2 1
1 3 1
2 3 1

样例输出
1

思路
利用矩阵树定理计算生成树个数,并计算每位所涉及的生成树数量,其总和/生成树总数即为解

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=105;
const int M=10005;
const int INF=0x3f3f3f3f;
const ll LINF=1e18;
const ull sed=31;
const ll mod=998244353;
const double eps=1e-6;
const double PI=acos(-1.0);
const double delta=0.993;
typedef pair<int,int>P;
typedef pair<double,double>Pd;
typedef pair<ll,int> plt;
typedef pair<ll,ll> pll;

template<class T>inline void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}

template<class T>inline void write(T x)
{
    if (x < 0) x = ~x + 1, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int n,m;
struct node
{
    int u,v;ll w;
}E[M];

ll qpow(ll a,ll b)
{
    ll ret=1;
    while (b)
    {
        if(b&1) ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}

struct Matrix_Tree
{
    ll a[N][N];
    Matrix_Tree () {memset(a,0,sizeof(a));}
    void init_cnt(ll val) 
    {
        memset(a,0,sizeof(a));
        for(int i=1;i<=m;i++)
        {
            int u=E[i].u,v=E[i].v;
            if(val==-1 || E[i].w&val)
            {
                a[u][u]++;a[v][v]++;
                a[u][v]--;a[v][u]--;
            }
        }
    }
    ll Guass()
    {
        ll ans=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[i][j]<0) a[i][j]=(a[i][j]+mod)%mod;
        for(int i=1;i<n;i++)
        {
            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+mod)%mod;
                    swap(a[i],a[j]);
                    ans=-ans;
                }
            }
            ans=ans*a[i][i]%mod;
            if(!ans) return 0;
        }
        return (ans+mod)%mod;
    }
}Tr;

int main() 
{
    // freopen("a.txt","r",stdin);
    int T;
    read(T);
    while (T--)
    {
        read(n);read(m);
        for(int i=1;i<=m;i++) 
        {
            read(E[i].u);read(E[i].v);read(E[i].w);
        }
        Tr.init_cnt(-1);
        ll inv=Tr.Guass();
        if(!inv)
        {
            puts("0");
            continue;
        }
        ll tot=0;
        for(int i=0;i<=30;i++)
        {
            Tr.init_cnt(1ll<<i);
            tot=(tot+Tr.Guass()*(1ll<<i)%mod)%mod;
        }
        printf("%lld\n",tot*qpow(inv,mod-2)%mod);
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值