题目链接: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 x × y − 1 m o d 998244353 x×y^{−1}\ mod\; 998244353 x×y−1 mod998244353 where x × y − 1 x×y^{−1} x×y−1 is the irreducible fraction representation of the result, where y − 1 y^{−1} 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 ) n(2≤n≤100) n(2≤n≤100)and m ( 1 ≤ m ≤ 1 0 4 ) m(1≤m≤10^4) 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 ≤ 1 0 9 , u ≠ v ) u,v,w(1≤u,v,≤n,1≤w≤10^9,u≠v) u,v,w(1≤u,v,≤n,1≤w≤109,u=v), space separated, denoting an weight edge between u u u and v v v has weight w w 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
题目大意:给你一个无向图,其中n个点,m条边,每个边的边权为 w i w_i wi,定义树的权为树的所有边的边权的按位与。现在我们随机选择该图的一个生成树,问其生成树的权期望是多少。
emmm,一眼就是矩阵树。。。但中间的边权就真的卡的死死的。。。不会算,后来看题解才知道的。
每一位的按位与过程都是独立的,那么我们对每一位建立一个其含该位的边的基尔霍夫矩阵,然后就可以得出在该位下可以得到多少个生成树,那么他对答案的贡献就是 a n s ∗ 2 i s u m ans*\frac{2^i}{sum} ans∗sum2i其中 i i i表示是第几位, a n s ans ans表示的是在该位下的生成树个数, s u m sum sum表示的是总的生成树的个数。
然后就可以开始跑矩阵树了,只不过需要注意的是,矩阵树的的高斯消元和一般的高斯消元不太一样,他是从2开始的!!!(一般的是从1开始的,然后很多时候就会得到0)这里就被卡了挺久的。接下来需要注意的是,100个点,1W条边,就算是完全图也没有这么多条边,所以他一定会存在重边,那么我们用vector保存就好了。
以下是AC代码:
#include
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;
}