ABC263 F - Tournament
DP + 优化转移
题意
有 个人排成一排,第 1,2 个进行比赛,第3,4 个进行比赛 . . . 第 个与 第 个进行比赛,输掉的被移除,下一轮则是剩下 个人重复之前操作,直到只剩一个人
有一个 的矩阵 C, 表示第 i 个人赢了 j 场的分数,若可以任意决定每场比赛的结果,求这 个人的分数和最大
思路
考虑在二叉树中进行DP
本来考虑的是 表示 u 子树中的最大分数和,但是 u 子树中胜出的那个人对之后还是有影响的,所以有后效性,要用 表示 u 子树中第 id 个人胜出了,此时的最大分数和
这样共有 个状态
转移
对于每个结点 u,遍历他所包含的叶子结点编号 i,i 作为这个子树的胜者
-
i 在 u 的左子树中, 设从叶子到 u 要赢 k 场(k 可由 u 的深度求出)
·答案由 i 赢到左儿子时左儿子的贡献 + i 赢 k 把的贡献 - i 赢 k - 1 把的贡献 + 右儿子无论谁赢的贡献最大值(反正都要被左儿子出来的 i 打败)
其中 可以再用 maxn[u] 表示 u 子树的最大值 dp 出来
-
i 在 u 的右子树,同理
注意若每个结点第二维都开 则空间不足,要根据它实际的叶子数开,或者滚动数组优化
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
#define endl "\n"
typedef long long ll;
typedef pair<int, int> PII;
const int N = 17;
vector<vector<ll> > f(1 << N);
int l[1 << N];
ll c[1 << N][N];
ll maxn[1 << N];
int n;
void dp(int u)
{
int h = __lg(u) + 1;
int k = n + 1 - h;
if (k == 0)
{
l[u] = u % (1 << n) + 1;
return;
}
dp(u << 1);
dp(u << 1 | 1);
int sz = 1 << k - 1;
l[u] = l[u << 1];
int L = l[u] - 1;
for (int i = 1; i <= sz; i++)
{
f[u][i] = f[u << 1][i] - c[L + i][k - 1] + c[L + i][k] + maxn[u << 1 | 1];
f[u][sz + i] = f[u << 1 | 1][i] - c[L + sz + i][k - 1] + c[L + sz + i][k] + maxn[u << 1];
maxn[u] = max({maxn[u], f[u][i], f[u][sz + i]});
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i < 1 << n; i++)
{
int h = n - (int)__lg(i);
f[i].resize((1 << h) + 2, 0);
}
for (int i = 1 << n; i < 1 << n + 1; i++)
f[i].resize(2, 0);
for (int i = 1; i <= 1 << n; i++)
for (int j = 1; j <= n; j++)
cin >> c[i][j];
dp(1);
cout << maxn[1] << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构