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