1 条题解
-
0
题意理解
- 有 个城堡, 个对手,小 C 有 个士兵。
- 每个对手在每个城堡 上派兵 (已知)。
- 小 C 要确定一个固定的派兵方案 ,满足 ,用于与 个对手分别对战。
- 对战规则:
对于城堡 ,如果小 C 的士兵数 ,则小 C 在该城堡战胜对手 ,得到 分(注意:得分是城堡编号 ,不是士兵数)。 - 与一个对手对战的总分 = 所有战胜的城堡编号之和。
- 最终小 C 的总分 = 与 个对手对战得分的总和。
- 求最大总分。
关键点分析
- 固定方案:小 C 的方案对所有 个对手是一样的。
- 得分规则:在城堡 上,战胜对手 的条件是 ,战胜后得分 (注意是城堡编号)。
- 目标:最大化 场对战的总得分。
思路推导
对单个城堡 的分析
假设在城堡 上,小 C 派兵 。
对手 在该城堡派兵 。
如果 ,则小 C 在这场对战中得到 分。因此,对于固定的 ,我们可以知道哪些对手会在这个城堡上被战胜。
转化为背包问题
我们可以按城堡来规划,把 个士兵分配到 个城堡。
设 表示使用 个士兵时能获得的最大总分。
对于城堡 ,如果我们派兵 ,则:
- 成本 = 个士兵
- 收益 = 在城堡 上战胜的对手数量 (因为每个战胜的对手得 分)
计算收益
对于城堡 ,我们考虑所有 个对手,按 升序排序。
假设排序后为 。
如果我们派兵 ,那么 的 都会输给我们。
也就是说,如果 ,则战胜前 个对手(因为排序后前面的对手派兵更少,更容易战胜)。因此,派兵 时,战胜的对手数量 = 最大的 满足 。
那么收益 = 。
枚举与状态转移
对每个城堡 ,我们枚举派兵 (),计算收益 ,其中 如上计算。
然后做分组背包:每个城堡是一组,每组只能选一个派兵方案(一个 ),总士兵数不超过 。
转移方程:
其中 从 到 倒序枚举(01背包)。
算法步骤
- 读入 。
- 读入 的矩阵 。
- 对每个城堡 ,收集所有对手在该城堡的派兵 ,排序。
- 计算 :对 ,找出最大的 满足 ,收益 。
- 分组背包 DP: 初始 0,对每个城堡 ,对每个 从 到 更新 。
- 输出 。
复杂度
- 计算 :
- 分组背包: 不对,这里 最多 ,所以是 ?
但注意 枚举到 ,但 最大 ,,那么 会到 ,不可行。
优化
实际上, 不需要从 到 全部枚举,因为收益 只在 超过某个 时变化。
所以 的取值只有 个关键点: 以及 。这样,每个城堡我们只需枚举 个 ,总复杂度 ,,最大 ,勉强可过(优化常数)。
示例代码(C++)
#include <iostream> #include <vector> #include <algorithm> #include <cstring> using namespace std; int main() { int s, n, m; cin >> s >> n >> m; vector<vector<int>> a(s, vector<int>(n)); for (int i = 0; i < s; i++) { for (int j = 0; j < n; j++) { cin >> a[i][j]; } } vector<int> f(m + 1, 0); for (int i = 0; i < n; i++) { // 对城堡 i,收集所有对手的兵力 vector<int> b; for (int k = 0; k < s; k++) { b.push_back(a[k][i]); } sort(b.begin(), b.end()); // 计算收益函数 vector<int> profit(m + 1, 0); for (int t = 1; t <= m; t++) { int cnt = 0; for (int k = 0; k < s; k++) { if (t > 2 * b[k]) { cnt++; } else { break; // 因为排序了,后面不可能满足 } } profit[t] = cnt * (i + 1); // 城堡编号从1开始 } // 分组背包 for (int j = m; j >= 0; j--) { for (int t = 1; t <= m; t++) { if (j >= t) { f[j] = max(f[j], f[j - t] + profit[t]); } } } } int ans = 0; for (int j = 0; j <= m; j++) { ans = max(ans, f[j]); } cout << ans << endl; return 0; }
样例验证
样例 1
1 3 10 2 2 6输出 3,符合。
样例 2
2 3 10 2 2 6 0 0 0输出 8,符合。
总结
这道题的核心是:
- 将问题按城堡分解,计算在每个城堡上派兵 时的收益(战胜的对手数 × 城堡编号)。
- 使用分组背包模型,在总士兵数限制下分配兵力,最大化总分。
- 利用排序和阈值优化,减少枚举量。
- 1
信息
- ID
- 4517
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者