CodeForces 1856E1 PermuTree (easy version)
考虑局部贪心,假设我们现在在 ,我们希望 不同子树中的 的对数尽量多。
我们实际上只关心子树内 的相对大小关系,不关心它们具体是什么。如果 只有两个儿子 ,我们可以让 子树内的 全部小于 子树内的 ,这样 作为 的贡献是 ,是最大的。
那么对于 有多个儿子的情况,推广可知相当于把 的儿子分成 两个集合,最大化 。考虑做一个 的 01 背包,若能把 分成大小为 的集合, 对答案的贡献是 。取这个的最大值即可。
01 背包暴力做即可,根据树形背包的那套理论,每个点对只会在 处被统计,所以时间复杂度 ,可以通过 E1。
code
// Problem: E1. PermuTree (easy version) // Contest: Codeforces - Codeforces Round 890 (Div. 2) supported by Constructor Institute // URL: https://codeforces.com/contest/1856/problem/E1 // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 5010; int n, sz[maxn]; bool f[maxn]; ll ans; vector<int> G[maxn]; void dfs(int u) { sz[u] = 1; vector<int> vc; for (int v : G[u]) { dfs(v); sz[u] += sz[v]; vc.pb(sz[v]); } mems(f, 0); f[0] = 1; int s = 0; for (int x : vc) { s += x; for (int j = s; j >= x; --j) { f[j] |= f[j - x]; } } ll mx = 0; for (int i = 0; i <= s; ++i) { if (f[i]) { mx = max(mx, 1LL * i * (s - i)); } } ans += mx; } void solve() { scanf("%d", &n); for (int i = 2, p; i <= n; ++i) { scanf("%d", &p); G[p].pb(i); } dfs(1); printf("%lld\n", ans); } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】