2025.03.13 CW 模拟赛 D. 依然

题面 & 题解

D. 依然

难度是倒序的.

思路

因为 \(i\)\(2i, 2i + 1\) 形成了一颗树的的结构, 我们可以考虑树上 DP.

\(f_{u, cnt, 0/1}\) 表示在 \(u\) 这颗子树内一共选了 \(cnt\) 个 1, 并且当前节点 \(u\) 选择的是 0 / 1 的最大值.

在转移时根据题目中给的 0, 1 同或运算判断是否需要加上左 / 右儿子的权值即可.

代码中分类比较详细, 转移也不难理解.

#include "iostream"
#include "algorithm"
#include "cstring"

using namespace std;

typedef long long ll;
#define ls (u << 1)
#define rs (ls | 1)

constexpr int N = 1e3 + 5;

int n, a[N], sz[N];
ll f[N][N][2];

void dfs(int u) {
	if (u > n) {
		f[u][0][0] = 0;
		return;
	}
	sz[u] = 1;
	dfs(ls), sz[u] += sz[ls];
	dfs(rs), sz[u] += sz[rs];
	for (int i = 0; i <= sz[ls]; ++i)
		for (int j = 0, tot; j <= sz[rs]; ++j) {
			tot = i + j;
			if (!i) {
				if (!j) {
					f[u][tot][0] = max(f[u][tot][0], f[ls][i][0] + f[rs][j][0] + a[ls] + a[rs]);
					f[u][tot + 1][1] = max(f[u][tot + 1][1], f[ls][i][0] + f[rs][j][0]);
				}
				else {
					f[u][tot][0] = max(f[u][tot][0], f[ls][i][0] + a[ls] + max(f[rs][j][0] + a[rs], f[rs][j][1]));
					f[u][tot + 1][1] = max(f[u][tot + 1][1], f[ls][i][0] + max(f[rs][j][0], f[rs][j][1] + a[rs]));
				}
			}
			else {
				if (!j) {
					f[u][tot][0] = max(f[u][tot][0], max(f[ls][i][0] + a[ls], f[ls][i][1]) + f[rs][j][0] + a[rs]);
					f[u][tot + 1][1] = max(f[u][tot + 1][1], max(f[ls][i][0], f[ls][i][1] + a[ls]) + f[rs][j][0]);
				}
				else {
					f[u][tot][0] = max(f[u][tot][0], max(f[ls][i][0] + a[ls], f[ls][i][1]) + max(f[rs][j][0] + a[rs], f[rs][j][1]));
					f[u][tot + 1][1] = max(f[u][tot + 1][1], max(f[ls][i][0], f[ls][i][1] + a[ls]) + max(f[rs][j][0], f[rs][j][1] + a[rs]));
				}
			}
		}
}

void init() {
	memset(f, 128, sizeof f);
	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> a[i];
}

void calculate() {
	dfs(1);
	cout << max(f[1][n / 2][0], f[1][n / 2][1]) << '\n';
}

void solve() {
	cin.tie(nullptr)->sync_with_stdio(false);
	init();
	calculate();
}

signed main() {
	solve();
	return 0;
}

结语

以后看到有依赖关系的式子可以考虑转到树上进行 DP.

posted @ 2025-03-13 20:31  Steven1013  阅读(10)  评论(0)    收藏  举报