【JZOJ 5153】樹形圖求和

題目

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章