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.

浙公网安备 33010602011771号