[ARC101E] Ribbons on Tree 题解
[ARC101E] Ribbons on Tree 题解
其实算一道好题了。
首先考虑不相关的 simple 的 dp。平凡的想法是设
由于
考虑钦定边不选择的操作如何实现。考虑钦定一些边不选之后树会变成一些个连通块。这样一来我们尝试考虑依据连通块来 dp。那么对于每一个连通块里的点我们是可以任意连边的,并且容易得到对于
对于图上计数问题通常的策略是枚举
那么转移方程就是好得到的,我们枚举点
对于时间复杂度,事实上枚举
整体上本题充分地考察选手综合运用容斥和 dp 知识解决问题的能力,环环相扣,解题逻辑清晰。是一道好题。
代码:
#include <bits/stdc++.h>
#define N 5005
#define int long long
#define mod 1000000007
using namespace std;
int n;
struct Node {
int to, nxt;
} e[N << 1];
int head[N], cnt;
void add(int u, int v) {
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int f[N][N], g[N];
int bas[N];
int siz[N];
void dfs(int x, int fa) {
siz[x] = f[x][1] = 1;
for (int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if (y == fa)
continue;
dfs(y, x);
for (int j = 1; j <= siz[x]; j++)
for (int k = 1; k <= siz[y]; k++) {
if (j + k <= n)
g[j + k] = (g[j + k] + f[x][j] * f[y][k] % mod) % mod;
g[j] = (g[j] - f[x][j] * f[y][k] % mod * bas[k] % mod + mod) % mod;
}
siz[x] += siz[y];
for (int j = 1; j <= siz[x]; j++)
f[x][j] = g[j], g[j] = 0;
}
}
int ans;
signed main() {
cin >> n;
for (int i = 1; i < n; i++) {
int x, y;
scanf("%lld%lld", &x, &y);
add(x, y);
add(y, x);
}
bas[0] = 1;
for (int i = 2; i <= n; i += 2)
bas[i] = bas[i - 2] * (i - 1) % mod;
dfs(1, 0);
for (int i = 2; i <= n; i += 2)
ans = (ans + f[1][i] * bas[i] % mod) % mod;
cout << ans << "\n";
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通