5899. 【NOIP2018模拟10.6】资源运输(矩阵树定理)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/82972713

题目大意:

要你求一张图的生成树的边权乘积期望。

思路:

这题是一个矩阵树和变元矩阵树定理的应用题,矩阵树可以求出来生成树的数量,变元后的矩阵树可以求出所有生成树乘积和,然后除一下就好了。
矩阵树写法如下:
先定义两个矩阵,一个是度数矩阵,一个是连接矩阵,用度数矩阵剪掉连接矩阵,然后去掉一行一列,然后高斯消元,把对角线所有数乘起来就好了。

程序:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
#define mo 998244353
#define N 305
using namespace std;

int n,m,x,y,z;
LL a[N][N],b[N][N];

LL mul(LL x,int y){
	if (y==1) return x;
	LL o=mul(x,y/2);
	o=(o*o)%mo;
	if (y%2==1) o=(o*x)%mo;
	return o;
}

LL det(){
	LL ans=1;
	for (int i=1;i<=n;i++){
		LL inv=mul(a[i][i],mo-2);
		for (int j=i+1;j<=n;j++){
			LL rate=a[j][i]*inv%mo;
			for (int k=i;k<=n;k++){
				a[j][k]=(a[j][k]+mo-rate*a[i][k]%mo)%mo;
			}
		}
		ans=(ans*a[i][i])%mo;
	}
	return ans;
}

int main(){
	freopen("avg.in","r",stdin);
	freopen("avg.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++) {
		scanf("%d%d%d",&x,&y,&z);
		a[x][y]=mo-1;
		a[y][x]=mo-1;
		a[x][x]++;
		a[y][y]++;
		b[x][y]=mo-z;
		b[y][x]=mo-z;
		b[x][x]=(b[x][x]+z)%mo;
		b[y][y]=(b[y][y]+z)%mo;
	}
	n--;
	LL B=det();
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=n;j++)
	  a[i][j]=b[i][j];
	LL A=det();
	printf("%lld",A*mul(B,mo-2)%mo);
}

猜你喜欢

转载自blog.csdn.net/qq872425710/article/details/82972713
今日推荐