CF917D Stranger Trees
题目传送门
分析:
我们设恰好\(k\)条边不重复的方案数为\(f(k)\)
再设钦定\(n-k-1\)条边与原来树上的边重合,剩下的边自由连接成树的方案数\(g(k)\)
于是得到一个公式:
\[g(k)=\sum_{i=0}^{k}\binom{k}{i}f(i)
\]
意义为枚举剩下的\(K\)条边有哪些不重合
于是我们二项式反演:
\[f(k)=\sum_{i=0}^{k}(-1)^{k-i}\binom{k}{i}g(i)
\]
知道了\(g\)我们就可以\(O(n^2)\)求\(f\)
考虑\(g(k)\)之中会有\(k+1\)个连通块,那么生成树的方案数为
\[n^{k-1}\prod_{i=1}^{k+1}a_i
\]
其中\(a_i\)表示每个连通块的大小,即在此连通块里选择一个点向其他连通块连边
我们想知道\(\prod_{i=1}^{k+1}a_i\)在所有情况下的总和
考虑\(DP\)
设\(f[u][i][0/1]\)表示在\(u\)为根的子树下,已经钦定\(sz[u]-i-1\)条边,\(u\)所在连通块是否已选择了一个点
列出\(DP\)式子
设\(g[i][0/1]\)为传递给下一次\(DP\)的临时变量
\(g[j+k][0]=f[u][j][0]*f[v][k][0]\)钦定这条父子边,\(u,v\)属于同一连通块未被选择
\(g[j+k][1]=f[u][j][0]*f[v][k][1]+f[u][j][1]*f[v][k][0]\)钦定这条父子边,\(u,v\)属于同一连通块其中被选择
\(g[j+k+1][0]=f[u][j][0]*f[v][k][1]\)不钦定这条父子边,\(u,v\)不属于同一连通块,\(v\)必须被选择,\(u\)继承原来的状态
\(g[j+k+1][1]=f[u][j][1]*f[v][k][1]\)不钦定这条父子边,\(u,v\)不属于同一连通块,\(v\)必须被选择,\(u\)继承原来的状态
总复杂度为\(O(n^2)\)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#include<bitset>
#include<string>
#define maxn 205
#define MOD 1000000007
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n;
int sz[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],cnt;
int f[maxn][maxn][2],g[maxn][2],ans[maxn],C[maxn][maxn];
inline int upd(int x){return x<MOD?x:x-MOD;}
inline int ksm(int num,int k)
{
int ret=1;
for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
return ret;
}
inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfs(int u,int fa)
{
sz[u]=f[u][0][0]=f[u][0][1]=1;
for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa)
{
int v=to[i];dfs(v,u);
for(int j=0;j<=sz[u]+sz[v];j++)g[j][0]=g[j][1]=0;
for(int j=0;j<=sz[u];j++)for(int k=0;k<=sz[v];k++)
{
g[j+k][0]=(g[j+k][0]+1ll*f[u][j][0]*f[v][k][0])%MOD;
g[j+k][1]=(g[j+k][1]+1ll*f[u][j][0]*f[v][k][1]+1ll*f[u][j][1]*f[v][k][0])%MOD;
g[j+k+1][0]=(g[j+k+1][0]+1ll*f[u][j][0]*f[v][k][1])%MOD;
g[j+k+1][1]=(g[j+k+1][1]+1ll*f[u][j][1]*f[v][k][1])%MOD;
}
sz[u]+=sz[v];
for(int j=0;j<=sz[u];j++)f[u][j][0]=g[j][0],f[u][j][1]=g[j][1];
}
}
int main()
{
n=getint();
for(int i=1;i<n;i++)
{
int u=getint(),v=getint();
newnode(u,v),newnode(v,u);
}
for(int i=0;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)C[i][j]=upd(C[i-1][j-1]+C[i-1][j]);
}
dfs(1,1);
ans[0]=1;
for(int i=1;i<n;i++)ans[i]=1ll*f[1][i][1]*ksm(n,i-1)%MOD;
for(int i=0;i<n;i++)for(int j=0;j<i;j++)ans[i]=upd(ans[i]-1ll*C[n-1-j][i-j]*ans[j]%MOD+MOD);
for(int i=n-1;~i;i--)printf("%d ",ans[i]);
}