题意
首先定义了一棵生成树的重量:这棵树所有边的按位与(AND)
给出一个无向连通图,随机挑选一个生成树,问这个生成树的重量的期望是多少。
矩阵树定理求的是
∑ T ∏ e ∈ T w e \sum\limits_{T}\prod_{e\in T}w_e T∑e∈T∏we
期望就是总权值除以生成树的个数
个数可以让边权为一来求解
总权值不好搞,但是 a n d and and操作可以拆分为二进制来看
对于每一位二进制来说不是 1 1 1就是 0 0 0
这样就可以使用矩阵树定理来求解每一位的贡献
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10009;
#define int long long
int a[109][109],n,m,l[maxn],r[maxn],w[maxn];
const int mod = 998244353;
int quick(int x,int n)
{
int ans = 1;
for( ; n ; n>>=1, x = x*x%mod)
if( n&1 ) ans = ans*x%mod;
return ans;
}
int det()
{
int ans = 1;
for(int i=2;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
if( !a[i][i]&&a[j][i] ){ swap(a[i],a[j]); ans = -ans; break;}
int inv = quick( a[i][i],mod-2 );
for(int j=i+1;j<=n;j++)
{
int temp = inv*a[j][i]%mod;
for(int q=i;q<=n;q++)
a[j][q] = ( a[j][q]-temp*a[i][q]%mod )%mod;
}
}
for(int i=2;i<=n;i++) ans = ans*a[i][i]%mod;
return ( ans+mod )%mod;
}
signed main()
{
int t;
cin >> t;
while( t-- )
{
cin >> n >> m;
for(int i=1;i<=m;i++)
cin >> l[i] >> r[i] >> w[i];
int ans = 0;
for(int i=0;i<=30;i++)
{
memset(a,0,sizeof(a));
for(int j=1;j<=m;j++)
{
int x = l[j],y = r[j],val = (bool)((1<<i)&w[j]);
a[x][x] = ( a[x][x]+val )%mod; a[y][y] = ( a[y][y]+val )%mod;
a[x][y] = ( a[x][y]-val )%mod; a[y][x] = ( a[y][x]-val )%mod;
}
ans = ( ans+det()%mod*(1<<i)%mod )%mod;
}
memset( a,0,sizeof(a) );
for(int i=1;i<=m;i++)
{
int x = l[i],y = r[i],val = 1;
a[x][x] = ( a[x][x]+val )%mod; a[y][y] = ( a[y][y]+val )%mod;
a[x][y] = ( a[x][y]-val )%mod; a[y][x] = ( a[y][x]-val )%mod;
}
ans = ans*quick(det(),mod-2)%mod;
ans = ( ans%mod+mod )%mod;
printf("%lld\n",ans);
}
}