#4707. 点分治
题解
问题在于两棵已经确定点分树的形态的树,合并后能形成多少种形态的点分树
考虑如果分裂 $(u,v)$ 这条边,那就相当于两个点分树黑白染色,各自找相同颜色的祖先,然后形成新的两个点分树
考虑如果连接 $(u,v)$ 的话,那应该就是 $u->rt_u$ 和 $v->rt_v$ 这两条路径可以任意顺序合并起来,所以考虑树形dp,类似背包转移即可
效率: $O(n^2)$
代码
#include <bits/stdc++.h> using namespace std; const int N=5005,P=1e9+7; int n,hd[N],V[N<<1],nx[N<<1],t,f[N][N],sz[N],c[N][N],g[N][N],F[N]; int X(int x){return x>=P?x-P:x;} void add(int u,int v){ nx[++t]=hd[u];V[hd[u]=t]=v; } void dfs(int u,int fr){ f[u][sz[u]=1]=1; for (int v,i=hd[u];i;i=nx[i]){ if ((v=V[i])==fr) continue; dfs(v,u); for (int j=1;j<=sz[u];j++) for (int i=0;i<=sz[v];i++) (F[i+j]+=1ll*f[u][j]*c[i+j-1][j-1]%P*g[v][i]%P)%=P; sz[u]+=sz[v]; for (int i=1;i<=sz[u];i++) f[u][i]=F[i],F[i]=0; } for (int i=sz[u];~i;i--) g[u][i]=(g[u][i+1]+f[u][i])%P; } int main(){ cin>>n;c[0][0]=1; for (int i=1;i<=n;i++){ c[i][0]=1; for (int j=1;j<=i;j++) c[i][j]=X(c[i-1][j]+c[i-1][j-1]); } for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); dfs(1,0);cout<<g[1][0]<<endl;return 0; }