CodeForces 1218A BubbleReactor

洛谷传送门

CF 传送门

虚高 *2800。放模拟赛 T2 人均切了。

考虑拎出环上的点,每个点下面都挂了一棵树。

那么可以预处理出每棵树从一个点开始染黑,这棵树对答案的贡献。因为一棵树染了一个点就只能去染子树了,所以这个贡献是固定的,用换根 dp 求即可。

那么我们现在可以在环上选择一个起点,每次可以把左端点或右端点往外拓展 1。拓展的贡献就是除了已经拓展的点外其他点挂的树的 sz 之和,加上要拓展的点的所有子树 sz 和。

套路区间 dp 即可。设 fi,j 为已经拓展了环上在 [i,j] 中的点即可。注意因为是个环所以 i>jfi,j 表示已经拓展了环上在 [i,m][1,j] 的点,其中 m 为环上的点数。

按长度从小到大枚举,就可以滚动数组了。

时间复杂度 O(n+m2)。实际跑得挺快。

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;
}
posted @   zltzlt  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示