专栏文章
题解:AT_abc287_f [ABC287F] Components
AT_abc287_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio0390f
- 此快照首次捕获于
- 2025/12/02 11:10 3 个月前
- 此快照最后确认于
- 2025/12/02 11:10 3 个月前
一个显然的树上背包。
设 表示以 为根的子树中有 个连通块,且 是否在点集中的方案数。
枚举 当前子树的连通块个数 , 的子节点 的连通块个数 ,转移方程:
- 不选, 随意:。
- 选, 不选:。
- 都选,此时 所在的连通块和 所在的连通块组成了一个大连通块:。
主要是代码的实现:
- 只有 的子树中至少有一个连通块时才能选 本身。
- 为了避免重算,需要将 复制到 中,将 清空,再使用 转移 。
- 记得取模。
代码
CPP#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 5050, MOD = 998244353;
int n, dp[N][N][2], t[N][2], sz[N];
vector<int> e[N];
void dfs(int now, int fa){
sz[now] = 1; dp[now][1][1] = dp[now][0][0] = 1;
for(int u : e[now]){
if(u == fa) continue;
dfs(u, now);
for(int i = 0; i <= sz[now]; i ++){
t[i][0] = dp[now][i][0];
t[i][1] = dp[now][i][1];
dp[now][i][0] = dp[now][i][1] = 0;
}
for(int i = 0; i <= sz[now]; i ++){
for(int j = 0; j <= sz[u]; j ++){
dp[now][i + j][0] = (dp[now][i + j][0] + (ll)t[i][0] * dp[u][j][0] % MOD) % MOD;
if(j > 0) dp[now][i + j][0] = (dp[now][i + j][0] + (ll)t[i][0] * dp[u][j][1] % MOD) % MOD;
if(i > 0) dp[now][i + j][1] = (dp[now][i + j][1] + (ll)t[i][1] * dp[u][j][0] % MOD) % MOD;
if(i > 0 && j > 0) dp[now][i + j - 1][1] = (dp[now][i + j - 1][1] + (ll)t[i][1] * dp[u][j][1] % MOD) % MOD;
}
}
sz[now] += sz[u];
}
}
int main() {
cin >> n;
for(int i = 1, u, v; i < n; i ++){
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0);
for(int j = 1; j <= n; j ++)
cout << (dp[1][j][0] + dp[1][j][1]) % MOD << endl;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...