1 条题解
-
0
CF1989C Two Movies 题解
题意简述
有两部电影, 个观众。第 个观众对第一部电影的评价为 ,对第二部的评价为 ,。
我们要为每个观众推荐去看其中一部电影(每人只看一部)。若观众去看电影 1,则电影 1 总分加上 ;若去看电影 2,则电影 2 总分加上 。公司最终得分为 两部电影总分的较小值。求这个最小值的最大值。
核心思路:贪心 + 平衡
设最终电影 1 的总分为 ,电影 2 的总分为 ,目标是最大化 。
对于每个观众 ,有两种选择:
- 选电影 1:贡献
- 选电影 2:贡献
第一步:确定明确优势的选择
若 ,则选电影 1 一定不劣:不仅让 增加了 ,还避免了 增加较小的 。同理,若 ,则选电影 2 一定不劣。
这些选择可以直接固定下来,不会漏掉最优解。
第二步:处理平局
对于 的情况,两种选择对两电影的影响是等效的:都会使某部电影增加 ,另一部不变。我们需要借助这些“可调”的分数来平衡 和 。
- 若 :相当于要扣掉某部电影的 1 分。为了最大化 ,应该扣掉当前较大者,使两者更接近。
- 若 :相当于赠送 1 分。应加给当前较小者,提升短板。
- 若 :分配不影响结果,可以忽略。
重复以上操作直到所有平局观众处理完毕,此时 即为答案。
正确性简要说明
先固定明确优势的选择不会丢失最优解,因为交换论证可证:若最优解中出现了违背的情况,可以交换得到不差的结果。
对于平局部分,每次局部最优的平衡操作可以通过调整法证明整体最小值的最大化。直觉上,我们的操作总是尽量让 和 接近,从而最大化较小值。
算法步骤
- 读取 和数组 。
- 初始化 ,。
- 遍历 :
- 若 ,;
- 若 ,;
- 若 ,将 存入暂存列表。
- 遍历暂存列表中的每个值 :
- 若 :若 则 ,否则 ;
- 若 :若 则 ,否则 ;
- 若 :忽略。
- 输出 。
复杂度
- 每组数据遍历数组 ,总 ,,总复杂度 ,可以在时限内轻松通过。
参考代码
#include <iostream> using namespace std; const int N = 200005; int t, n; int a[N], b[N]; int ansa, ansb; int c[N], s; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> t; while (t--) { ansa = ansb = s = 0; cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; for (int i = 1; i <= n; ++i) cin >> b[i]; // 第一步:处理 a_i > b_i 或 b_i > a_i 的情况 for (int i = 1; i <= n; ++i) { if (a[i] > b[i]) ansa += a[i]; else if (b[i] > a[i]) ansb += b[i]; else c[++s] = a[i]; // a[i] == b[i] } // 第二步:处理平局,用 c[i] 平衡两分数 for (int i = 1; i <= s; ++i) { if (c[i] < 0) { // -1 if (ansa >= ansb) ansa -= 1; else ansb -= 1; } else if (c[i] > 0) { // +1 if (ansa >= ansb) ansb += 1; else ansa += 1; } // c[i] == 0 不操作 } cout << min(ansa, ansb) << '\n'; } return 0; }
- 1
信息
- ID
- 6889
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者