题目
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);
}