【CF917D】Stranger Trees

题目

题目链接:https://codeforces.com/problemset/problem/917/D
给出 (n) 个点的一棵树,求在 (n) 个点的完全图的所有生成树中,与给出的树边数有 (k) 条重合的生成树数量。对于每一个 (kin [0,n)∩mathrm{Z}) 输出结果模 (10^9+7) 后的值。
(nleq 100)

思路

把给出的树中的边的边权设为 (x),其他边边权设为 (1),那么对于完全图中任意一棵生成树 (mathrm{T}),设其边权积为 (s),它与给定的树重合的边的数量即为 (log_x s)
那么我们枚举 (x=1sim n),分别矩阵树定理,设 (f_i) 表示 (x=i) 时所有生成树权值之和。设当 (x=i) 时,与给定的树重合边数为 (j) 的生成树数量为 (g_{i,j}),那么我们可以得到

[left{egin{matrix} 1^0g_{1,0}+1^1g_{1,1}+cdots+1^{n-1}g_{1,n}=f_1 \ 2^0g_{2,0}+2^1g_{2,1}+cdots+2^{n-1}g_{2,n}=f_2 \ vdots \ n^0g_{n,0}+n^1g_{n,1}+cdots+n^{n-1}g_{n,n}=f_n end{matrix} ight.]

高斯消元即可。
时间复杂度 (O(n^4))

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=105,MOD=1000000007;
int n,G[N][N];
ll f[N],g[N][N];

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

ll dit()
{
	ll tag=1,res=1;
	for (int i=1;i<n;i++)
	{
		for (int j=i;j<n;j++)
			if (g[j][i])
			{
				if (i!=j) tag=-tag;
				for (int k=1;k<n;k++)
					swap(g[j][k],g[i][k]);
				break;
			}
		ll inv=fpow(g[i][i],MOD-2);
		for (int j=i+1;j<n;j++)
			if (g[j][i])
			{
				ll base=inv*g[j][i]%MOD;
				for (int k=1;k<n;k++)
					g[j][k]=((g[j][k]-base*g[i][k])%MOD+MOD)%MOD;
			}
	}
	for (int i=1;i<n;i++) res=res*g[i][i]%MOD;
	return (res*tag+MOD)%MOD;
}

void gauss()
{
	for (int i=1;i<=n;i++)
	{
		for (int j=i;j<=n;j++)
			if (g[j][i])
			{
				for (int k=1;k<=n;k++)
					swap(g[i][k],g[j][k]);
				swap(f[i],f[j]);
				break;
			}
		ll inv=fpow(g[i][i],MOD-2);
		for (int j=i+1;j<=n;j++)
			if (g[j][i])
			{
				ll base=g[j][i]*inv%MOD;
				for (int k=1;k<=n;k++)
					g[j][k]=((g[j][k]-g[i][k]*base)%MOD+MOD)%MOD;
				f[j]=((f[j]-f[i]*base)%MOD+MOD)%MOD;
			}
	}
	for (int i=n;i>=1;i--)
	{
		ll sum=0;
		for (int j=i+1;j<=n;j++)
			sum=(sum+g[i][j]*f[j])%MOD;
		f[i]=(f[i]-sum+MOD)*fpow(g[i][i],MOD-2)%MOD;
	}
}

int main()
{
	scanf("%d",&n);
	for (int i=1,x,y;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		G[x][y]=G[y][x]=1;
	}
	for (int i=1;i<=n;i++)
	{
		memset(g,0,sizeof(g));
		for (int j=1;j<=n;j++)
			for (int k=1;k<=n;k++)
				if (j!=k && G[j][k])
					g[j][k]=MOD-i,g[j][j]=(g[j][j]+i)%MOD;
				else if (j!=k)
					g[j][k]=MOD-1,g[j][j]=(g[j][j]+1)%MOD;
		f[i]=dit();
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			g[i][j]=fpow(i,j-1);
	gauss();
	for (int i=1;i<=n;i++)
		printf("%d ",f[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/stoorz/p/14296389.html