题目
题目链接: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;
}