[題解]AT_abc287_f [ABC287F] Components

WaterSunHB發表於2024-06-23

思路

定義 \(dp_{i,j,0/1}\) 表示在以 \(i\) 為根的子樹中(包括 \(i\))選出 \(j\) 個連通塊,且 \(i\) 不選/選 的方案數。

假設我們在 DFS 過程中,當前列舉到以 \(u\) 為根節點的情況,那麼顯然有 \(dp_{u,0,0} = dp_{u,1,1} = 1\)

然後,我們從 \(u\) 開始向其兒子節點搜尋,假設當前列舉到的點是 \(v\)

那麼,我們對於每一個 \(v\),我們都可以對 \(u\) 的選取情況作分類討論(其中 \(a,b\) 表示以 \(u\) 為根的子樹在沒有 \(v\) 之前的連通塊數量,和以 \(v\) 為根的子樹中連通塊的數量):

  1. 如果不選,那麼兩棵子樹合併,連通塊數量為 \(a + b\),那麼有 \(dp_{u,a + b,0} \leftarrow dp_{u,a + b,0} + dp_{u,a,0} \times (dp_{v,b,0} + dp_{v,b,1})\)
  2. 如果選,那麼還需要根據 \(v\) 的選取情況進行分類討論:
    • 如果 \(v\) 不選,那麼兩棵子樹合併,連通塊數量還是為 \(a + b\),那麼有 \(dp_{u,a + b,1} \leftarrow dp_{u,a + b,1} + dp_{u,a,1} \times dp_{v,b,0}\)
    • 如果 \(v\) 選,那麼兩棵子樹合併,由於 \(u,v\) 都要選,那麼,包含 \(u,v\) 的兩個連通塊將合併為一個,所以連通塊數量為 \(a + b - 1\),那麼有 \(dp_{u,a + b - 1,1} \leftarrow dp_{u,a + b - 1,1} + dp_{u,a,1} \times dp_{v,b,1}\)

Code

#include <bits/stdc++.h>  
#define int long long  
#define re register  
  
using namespace std;  
  
const int N = 5010,M = 1e4 + 10,mod = 998244353;  
int n;  
int idx,h[N],e[M],ne[M];  
int dp[N][N][2];  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 1) + (r << 3) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
inline void add(int a,int b){  
    ne[idx] = h[a];  
    e[idx] = b;  
    h[a] = idx++;  
}  
  
inline int dfs(int u,int fa){  
    int sz = 1;  
    dp[u][0][0] = dp[u][1][1] = 1;  
    for (re int i = h[u];~i;i = ne[i]){  
        int j = e[i];  
        if (j == fa) continue;  
        int ssz = dfs(j,u);  
        for (re int a = sz;~a;a--){  
            for (re int b = ssz;b;b--) dp[u][a + b][0] = (dp[u][a + b][0] + dp[u][a][0] * (dp[j][b][0] + dp[j][b][1]) % mod) % mod;  
            // b 不能列舉到 0,因為如果 b 列舉到 0,那麼將會有 dp[u][a][0] = 2 * dp[u][a][0] % mod,然而這種狀態肯定是我們計算過的,所以不能列舉到 0   
        }  
        for (re int a = sz;a;a--){  
            for (re int b = ssz;b;b--){  
                dp[u][a + b][1] = (dp[u][a + b][1] + dp[u][a][1] * dp[j][b][0] % mod) % mod;  
                dp[u][a + b - 1][1] = (dp[u][a + b - 1][1] + dp[u][a][1] * dp[j][b][1] % mod) % mod;  
            }  
        }  
        sz += ssz;  
    }  
    return sz;  
}  
  
signed main(){  
    memset(h,-1,sizeof(h));  
    n = read();  
    for (re int i = 1;i < n;i++){  
        int a,b;  
        a = read();  
        b = read();  
        add(a,b);  
        add(b,a);  
    }  
    dfs(1,-1);  
    for (re int i = 1;i <= n;i++) printf("%lld\n",(dp[1][i][0] + dp[1][i][1]) % mod);  
    return 0;  
}  

相關文章