【CF917D】Stranger Trees
题目
题目链接:https://codeforces.com/problemset/problem/917/D
给出 \(n\) 个点的一棵树,求在 \(n\) 个点的完全图的所有生成树中,与给出的树边数有 \(k\) 条重合的生成树数量。对于每一个 \(k\in [0,n)∩\mathrm{Z}\) 输出结果模 \(10^9+7\) 后的值。
\(n\leq 100\)。
思路
把给出的树中的边的边权设为 \(x\),其他边边权设为 \(1\),那么对于完全图中任意一棵生成树 \(\mathrm{T}\),设其边权积为 \(s\),它与给定的树重合的边的数量即为 \(\log_x s\)。
那么我们枚举 \(x=1\sim n\),分别矩阵树定理,设 \(f_i\) 表示 \(x=i\) 时所有生成树权值之和。设当 \(x=i\) 时,与给定的树重合边数为 \(j\) 的生成树数量为 \(g_{i,j}\),那么我们可以得到
\[\left\{\begin{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}\right.\]
高斯消元即可。
时间复杂度 \(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;
}