題目
Description
Input
Output
Sample Input
見附加文件
Sample Output
見附加文件
Data Constraint
思路
矩陣樹定理
我們考慮分別計算每一條邊對答案的貢獻;即需要對於每一條邊得知包含它的樹形圖個數有多少個。
對於樹形圖計數,可以考慮用基爾霍夫矩陣求解。於是樸素的想法就是對於每一條邊,將它相連的兩個端點合併成一個點,然後求出樹形圖個數以更新答案。
事實上,包含一條邊的樹形圖個數,就是總共的樹形圖個數減去不包含這條邊的樹形圖個數。而不包含這條邊的樹形圖個數,就相當於在基爾霍夫矩陣某一行修改兩個值後的矩陣的行列式。
於是這道題就很簡單了
代碼
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
ll power(ll x,ll y)
{
ll b=1;
while(y)
{
if(y&1) b=b*x%mod;
x=x*x%mod; y>>=1;
}
return b;
}
int n,m;
struct nod
{
int x,y,z;
} b[100005];
const int N = 305;
ll a[N][N],c[N][N];
ll yjy;
void work(ll (*a)[N],ll (*b)[N],int n)
{
yjy = 1;
for(int i=1; i<=n; i++) b[i][i] = 1;
for(int i=1; i<=n; i++)
{
int u = -1;
for(int j=i; j<=n; j++) if(a[j][i])
{
u=j; break;
}
if(u==-1)
{
yjy=0; return;
}
if(u!=i)
{
for(int k=1; k<=n; k++) swap(a[i][k],a[u][k]),swap(b[i][k],b[u][k]);
yjy*=-1;
}
ll v=power(a[i][i],mod-2);
yjy=yjy*a[i][i]%mod;
for(int k=1; k<=n; k++) a[i][k]=a[i][k]*v%mod,b[i][k]=b[i][k]*v%mod;
for(int j=1; j<=n; j++) if(i!=j&&a[j][i])
{
ll v=a[j][i];
for(int k=1; k<=n; k++) a[j][k]=(a[j][k]-a[i][k]*v)%mod,b[j][k]=(b[j][k]-b[i][k]*v)%mod;
}
}
}
int main()
{
// freopen("calc.in","r",stdin); freopen("calc.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].z);
a[b[i].x][b[i].x]++;
a[b[i].x][b[i].y]--;
}
work(a,c,n-1);
ll ans=0;
for(int i=1; i<=m; i++)
{
int x=b[i].x;
if(x==n) continue;
ans=(ans+(yjy*(c[b[i].x][x]-c[b[i].y][x]))%mod*b[i].z)%mod;
}
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans);
}