D e s c r i p t i o n \mathscr{Description} Description
一棵树删k条边,再加k条边还是树,求方案数
S o l u t i o n \mathscr{Solution} Solution
前置知识:prufer序列
- 设有k个连通块,k-1条边,则prufer序列长度为k-2
- 每个位置可填1~n ⇒ n k − 2 \Rightarrow n^{k-2} ⇒nk−2
- 每条边联通连通块时可以连 s i s_i si个节点中任意一个
- 综上可得
n k − 2 ∗ ∏ i = 1 k s i n^{k-2}*\mathop{\prod}\limits^{k}_{i=1}s_i nk−2∗i=1∏ksi (k为联通块数量, s i s_i si为联通块大小)
- 本题中 n k − 1 ∗ ∏ i = 1 k + 1 s i n^{k-1}*\mathop{\prod}\limits^{k+1}_{i=1}s_i nk−1∗i=1∏k+1si(k条边k+1个联通块)
求 ∏ i = 1 k s i \mathop{\prod}\limits^{k}_{i=1}s_i i=1∏ksi:树形DP
问题等价于
n
n
n点树分成
k
+
1
k+1
k+1个连通块,并在每个连通块中任选一点的方案数
设
d
p
i
,
j
,
t
dp_{i,j,t}
dpi,j,t表示以i为根的子树中分为j个连通块,i点所在块中是否已选点方案数
{ t = 0 ⇒ 未 选 点 t = 1 ⇒ 已 选 点 \left\{ \begin{aligned} t & = 0 \Rightarrow 未选点 \\ t & = 1 \Rightarrow 已选点 \end{aligned} \right. {tt=0⇒未选点=1⇒已选点
for son
for j i的联通块数
for k son的连通块数
t
a
s
k
:
将
s
o
n
子
树
中
连
通
块
合
并
到
i
上
task:将son子树中连通块合并到i上
task:将son子树中连通块合并到i上
C a s e 1 : i 块 中 的 点 在 i 的 祖 先 处 已 经 选 好 ⇒ d p i , j , 0 Case \,\,\,1:i块中的点在i的祖先处已经选好\Rightarrow dp_{i,j,0} Case1:i块中的点在i的祖先处已经选好⇒dpi,j,0
-
i 与 s o n 不 删 边 ⇒ s o n 中 不 选 点 , 并 入 i 中 i与son 不删边 \Rightarrow son中不选点,并入i中 i与son不删边⇒son中不选点,并入i中
⟹ d p i , j , 0 + = d p i , j − k + 1 , 0 ∗ d p s o n , k , 0 \Longrightarrow\,\,dp_{i,j,0}+=dp_{i,j-k+1,0}*dp_{son,k,0} ⟹dpi,j,0+=dpi,j−k+1,0∗dpson,k,0 -
i 与 s o n 删 边 , 不 管 s o n ⇒ s o n 中 必 须 选 点 ( 每 块 至 少 一 点 ) , 并 入 i 中 i与son删边,不管son\Rightarrow son中必须选点(每块至少一点),并入i中 i与son删边,不管son⇒son中必须选点(每块至少一点),并入i中
⟹ d p i , j , 0 + = d p i , j − k , 0 ∗ d p s o n , k , 1 \Longrightarrow\,\,dp_{i,j,0}+=dp_{i,j-k,0}*dp_{son,k,1} ⟹dpi,j,0+=dpi,j−k,0∗dpson,k,1
C a s e 2 : i 块 中 的 点 在 i 的 子 树 中 ⇒ d p i , j , 1 Case \,\,\,2:i块中的点在i的子树中\Rightarrow dp_{i,j,1} Case2:i块中的点在i的子树中⇒dpi,j,1
-
不 删 边 , 点 在 i 这 块 中 不删边,点在i这块中 不删边,点在i这块中
⟹ d p i , j , 1 + = d p i , j − k + 1 , 1 ∗ d p s o n , k , 0 \Longrightarrow\,\,dp_{i,j,1}+=dp_{i,j-k+1,1}*dp_{son,k,0} ⟹dpi,j,1+=dpi,j−k+1,1∗dpson,k,0 -
不 删 边 , 点 在 s o n 这 块 中 不删边,点在son这块中 不删边,点在son这块中
⟹ d p i , j , 1 + = d p i , j − k + 1 , 0 ∗ d p s o n , k , 1 \Longrightarrow\,\,dp_{i,j,1}+=dp_{i,j-k+1,0}*dp_{son,k,1} ⟹dpi,j,1+=dpi,j−k+1,0∗dpson,k,1 -
删 边 隔 离 , i 和 s o n 中 都 有 点 删边隔离,i和son中都有点 删边隔离,i和son中都有点
⟹ d p i , j , 1 + = d p i , j − k , 1 ∗ d p s o n , k , 1 \Longrightarrow\,\,dp_{i,j,1}+=dp_{i,j-k,1}*dp_{son,k,1} ⟹dpi,j,1+=dpi,j−k,1∗dpson,k,1
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e4+10,K=110,M=998244353;
int n,k,sz[N],tot,h[N];
struct Edge{int v,nxt;}e[N<<1];
void add(int a,int b){e[++tot].v=b,e[tot].nxt=h[a],h[a]=tot;}
int dp[N][K][2],pre[K][2];
void dfs(int x,int fx){
sz[x]=1;
dp[x][1][0]=dp[x][1][1]=1;
for(int i=h[x],v;i;i=e[i].nxt)if((v=e[i].v)!=fx)
{
dfs(v,x);
memcpy(pre,dp[x],sizeof(pre));
memset(dp[x],0,sizeof(dp[x]));
for(int y=1;y<=min(sz[x],k+1);y++)
for(int z=1;z<=min(sz[v],k+1)&&y+z-1<=k+1;z++)
dp[x][y+z-1][0]=(dp[x][y+z-1][0]+1ll*pre[y][0]*dp[v][z][0])%M,
dp[x][y+z][0]=(dp[x][y+z][0]+1ll*pre[y][0]*dp[v][z][1])%M,
dp[x][y+z-1][1]=(dp[x][y+z-1][1]+1ll*pre[y][1]*dp[v][z][0])%M,
dp[x][y+z-1][1]=(dp[x][y+z-1][1]+1ll*pre[y][0]*dp[v][z][1])%M,
dp[x][y+z][1]=(dp[x][y+z][1]+1ll*pre[y][1]*dp[v][z][1])%M;
sz[x]+=sz[v];
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1,0);
int ans=dp[1][k+1][1];
for(int i=1;i<k;i++)
ans=1ll*ans*n%M;
printf("%d\n",ans);
}