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;
}