CodeForces 1218A BubbleReactor
虚高 *2800。放模拟赛 T2 人均切了。
考虑拎出环上的点,每个点下面都挂了一棵树。
那么可以预处理出每棵树从一个点开始染黑,这棵树对答案的贡献。因为一棵树染了一个点就只能去染子树了,所以这个贡献是固定的,用换根 dp 求即可。
那么我们现在可以在环上选择一个起点,每次可以把左端点或右端点往外拓展 。拓展的贡献就是除了已经拓展的点外其他点挂的树的 之和,加上要拓展的点的所有子树 和。
套路区间 dp 即可。设 为已经拓展了环上在 中的点即可。注意因为是个环所以 时 表示已经拓展了环上在 的点,其中 为环上的点数。
按长度从小到大枚举,就可以滚动数组了。
时间复杂度 。实际跑得挺快。
code
#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 = 15010; int n, m; vector<int> G[maxn]; int deg[maxn], g[maxn], sz[maxn], h[maxn]; int f[2][maxn], a[maxn], b[maxn], c[maxn], mx; void dfs(int u, int fa) { sz[u] = 1; for (int v : G[u]) { if (v == fa || deg[v]) { continue; } dfs(v, u); sz[u] += sz[v]; g[u] += g[v]; } g[u] += sz[u]; } void dfs2(int u, int fa) { mx = max(mx, h[u]); for (int v : G[u]) { if (v == fa || deg[v]) { continue; } h[v] = h[u] + n - sz[v] * 2; dfs2(v, u); } } bool vis[maxn]; int p[maxn]; void dfs3(int u) { vis[u] = 1; p[m++] = u; for (int v : G[u]) { if (deg[v] && !vis[v]) { dfs3(v); break; } } } void solve() { scanf("%d", &n); for (int _ = 0, u, v; _ < n; ++_) { scanf("%d%d", &u, &v); ++u; ++v; ++deg[u]; ++deg[v]; G[u].pb(v); G[v].pb(u); } m = 0; queue<int> q; for (int i = 1; i <= n; ++i) { if (deg[i] == 1) { q.push(i); } } while (q.size()) { int u = q.front(); q.pop(); deg[u] = 0; for (int v : G[u]) { if (deg[v] && (--deg[v]) == 1) { q.push(v); } } } for (int i = 1; i <= n; ++i) { if (deg[i]) { dfs3(i); break; } } for (int i = 0; i < m; ++i) { int u = p[i]; dfs(u, -1); h[u] = g[u] + n - sz[u]; mx = 0; dfs2(u, -1); a[i] = g[u]; b[i] = mx; c[i] = sz[u]; } for (int i = 1; i < m; ++i) { c[i] += c[i - 1]; } mems(f, -0x3f); for (int i = 0; i < m; ++i) { f[1][i] = b[i]; } for (int p = 2, o = 0; p <= m; ++p, o ^= 1) { mems(f[o], -0x3f); for (int i = 0, j = p - 1; i < m; ++i, j = (j == m - 1 ? 0 : j + 1)) { f[o][i] = max(f[o ^ 1][i] + a[j], f[o ^ 1][i == m - 1 ? 0 : i + 1] + a[i]); if (p < m) { f[o][i] += c[m - 1]; if (i <= j) { f[o][i] -= c[j] - (i == 0 ? 0 : c[i - 1]); } else { f[o][i] -= c[m - 1] - c[i - 1] + c[j]; } } } } int ans = 0; for (int i = 0; i < m; ++i) { ans = max(ans, f[m & 1][i]); } printf("%d\n", ans); } int main() { // freopen("B.in", "r", stdin); // freopen("my.out", "w", stdout); int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话