题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6836
博客园食用链接:https://www.cnblogs.com/lonely-wind-/p/13449312.html
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 where is the irreducible fraction representation of the result, where 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 and in the first line, the number of nodes and the number of edges.
Then follows m lines, each contains three integers , space separated, denoting an weight edge between and has weight .
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
题目大意:给你一个无向图,其中n个点,m条边,每个边的边权为 ,定义树的权为树的所有边的边权的按位与。现在我们随机选择该图的一个生成树,问其生成树的权期望是多少。
emmm,一眼就是矩阵树。。。但中间的边权就真的卡的死死的。。。不会算,后来看题解才知道的。
每一位的按位与过程都是独立的,那么我们对每一位建立一个其含该位的边的基尔霍夫矩阵,然后就可以得出在该位下可以得到多少个生成树,那么他对答案的贡献就是 其中 表示是第几位, 表示的是在该位下的生成树个数, 表示的是总的生成树的个数。
然后就可以开始跑矩阵树了,只不过需要注意的是,矩阵树的的高斯消元和一般的高斯消元不太一样,他是从2开始的!!!(一般的是从1开始的,然后很多时候就会得到0)这里就被卡了挺久的。接下来需要注意的是,100个点,1W条边,就算是完全图也没有这么多条边,所以他一定会存在重边,那么我们用vector保存就好了。
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mac=200;
const int mod=998244353;
vector<int>mp[mac][mac];
ll mat[mac][mac];
int n,m;
ll qpow(ll a,ll b)
{
ll ans=1;
while (b){
if (b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll guass()
{
ll ans=1;
for (int i=2; i<=n; i++){
for (int j=i+1; j<=n; j++)
while (mat[j][i]){
ll p=mat[i][i]/mat[j][i];
for (int k=i; k<=n; k++)
mat[i][k]=(mat[i][k]-mat[j][k]*p%mod+mod)%mod;
swap(mat[i],mat[j]);
ans=-ans;
}
ans=ans*mat[i][i]%mod;
}
return (ans+mod)%mod;
}
int main(int argc, char const *argv[])
{
int t;
scanf ("%d",&t);
while (t--){
scanf ("%d%d",&n,&m);
for (int i=1; i<=m; i++){
int u,v,w;
scanf ("%d%d%d",&u,&v,&w);
mp[u][v].push_back(w); mp[v][u].push_back(w);
mat[u][v]--; mat[v][u]--;
mat[u][u]++; mat[v][v]++;
}
ll ans=qpow(guass(),mod-2);
ll fz=0;
for (int wei=0; wei<=30; wei++){
memset(mat,0,sizeof mat);
for (int i=1; i<=n; i++)
for (int j=i+1; j<=n; j++){
for (auto x:mp[i][j]){
if (x&(1<<wei)){
mat[i][j]--; mat[j][i]--;
mat[i][i]++; mat[j][j]++;
}
}
}
fz=(fz+qpow(2,wei)*guass()%mod)%mod;
}
memset(mat,0,sizeof mat);
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) mp[i][j].clear();
printf("%lld\n",ans*fz%mod);
}
return 0;
}