[JZOJ5899]【NOIP2018模擬10.6】資源運輸【矩陣樹定理】【圖論】
阿新 • • 發佈:2018-11-10
Description
給定一個n個點,m條邊的帶權無向圖。
定義這個圖的一個生成樹的權值為生成樹上邊權的乘積。
求所有生成樹權值的平均值,答案對998244353取模。
2<=n<=300,n-1<=m<=1000
Solution
平均值=和/總數
總數很容易求,就是無向圖生成樹計數,利用矩陣樹定理,求出這個圖的基爾霍夫矩陣(就是度數矩陣(Ai,i=degree[i])-鄰接矩陣),答案就是基爾霍夫矩陣挖掉第i行第i列(i可以任意取),用高斯消元求出挖掉以後矩陣行列式的值即可…
和的話,我們有變元矩陣樹定理
把求基爾霍夫矩陣時的度數改成出邊邊權和,鄰接矩陣0/1改成邊權,一樣做生成樹計數就是答案…
證明同矩陣樹定理的證明是類似的。
總時間複雜度
不會生成樹計數的同學參考:
不明白NOIP模擬為什麼要考生成樹計數…為什麼要出一道板題…
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 305
#define mo 998244353
#define LL long long
using namespace std;
int n,m;
LL a[2][N][N],t[2];
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
void gauss(int p)
{
fo(i,1,n-1)
{
fo(k,i,n-1)
{
if(a[p][k][i]>0)
{
if(k!=i) {t[p]=-t[p];swap(a[p][k],a[p][i]);}
break;
}
}
a[p][i][i]=(a[p][i][i]+mo)%mo;
LL v=ksm(a[p][i][i],mo-2);
fo(k,i+1,n-1)
{
LL v1=(a[p][k][i]*v%mo+mo)%mo;
if(v1!=0)
fo(j,i,n-1)
a[p][k][j]=(a[p][k][j]-v1*a[p][i][j]%mo+mo)%mo;
}
}
}
int main()
{
cin>>n>>m;
t[0]=t[1]=1;
fo(i,1,m)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[0][x][y]--,a[0][y][x]--,a[0][x][x]++,a[0][y][y]++;
(a[1][x][y]+=mo-z)%=mo,(a[1][y][x]+=mo-z)%=mo,(a[1][x][x]+=z)%=mo,(a[1][y][y]+=z)%=mo;
}
gauss(0);
gauss(1);
LL s1=1,s=1;
fo(i,1,n-1) s1=s1*a[0][i][i]%mo,s=s*a[1][i][i]%mo;
s=(s*t[0]+mo)%mo,s1=(s1*t[1]+mo)%mo;
printf("%lld\n",s*ksm(s1,mo-2)%mo);
}