「Luogu P2123」皇后游戏

题目

皇后有 \(n\) 位大臣,每位大臣的左右手上面分别写上了一个正整数。恰逢国庆节来临,皇后决定为 \(n\) 位大臣颁发奖金,其中第 \(i\) 位大臣所获得的奖金数目为第 \(i - 1\) 位大臣所获得奖金数目与前 \(i\) 位大臣左手上的数的和的较大值再加上第 \(i\) 位大臣右手上的数。

形式化地讲:我们设第 \(i\) 位大臣左手上的正整数为 \(a_i\),右手上的正整数为 \(b_i\),则第 \(i\) 位大臣获得的奖金数目为 \(c_i\) 可以表达为:

\[c_{i} = \begin{cases} a_{1}+b_{1} & ,i=1 \\ \displaystyle \max \left \{ c_{i-1},\sum_{j=1}^{i}a_{j} \right \} +b_{i} & ,2\leq i \leq n \end{cases} \]

当然,吝啬的皇后并不希望太多的奖金被发给大臣,所以她想请你来重新安排一下队伍的顺序,使得获得奖金最多的大臣,所获奖金数目尽可能的少。

注意:重新安排队伍并不意味着一定要打乱顺序,我们允许不改变任何一位大臣的位置。

Luogu

分析

可以发现这道题的套路和 国王游戏 很像, 于是我们尝试邻项交换推式子.

考虑当前排列的第 \(i\) 和第 \(i+1\) 位大臣. 记 \(S = \sum_{j=1}^{i-1}a_{j}\), \(c_{i}\)\(c_{i}^{\prime}\) 分别为交换前和交换后排在第 \(i\) 位的大臣的奖金. 我们有

\[\begin{aligned} c*{i} &= \max\{c*{i-1}, S+a*{i}\} + b*{i} \\ c*{i+1} &= \max\{c*{i}, S+a*{i}+a*{i+1}\} + b*{i+1} > c*{i} \\ c*{i}^{\prime} &= \max\{c*{i-1}, S+a*{i+1}\} + b*{i+1} \\ c*{i+1}^{\prime} &= \max\{c*{i}^{\prime}, S+a*{i}+a*{i+1}\} + b*{i} > c*{i}^{\prime} \end{aligned} \]

若不换更优的话, 就需要 \(c_{i+1} \leq c_{i+1}^{\prime}\), 即

\[\max\{c_{i}, S+a_{i}+a_{i+1}\} + b_{i+1} \leq \max\{c_{i}^{\prime}, S+a_{i}+a_{i+1}\} + b_{i} \]

拆开得

\[\begin{aligned} &\max\{c*{i-1}+b*{i}+b*{i+1}, S+a*{i}+b*{i}+b*{i+1}, S+a*{i}+a*{i+1}+b*{i+1}\} \\ \leq &\max\{c*{i-1}+b*{i+1}+b*{i}, S+a*{i+1}+b*{i}+b*{i+1}, S+a*{i}+a*{i+1}+b*{i}\} \end{aligned} \]

把公共项 \(c_{i-1}+b_{i}+b_{i+1}\) 去掉不影响原条件式成立的充分必要性 (想一想, 为什么?), 于是得到

\[\max\{a_{i+1}, b_{i}\} + a_{i} + b_{i+1} \leq \max\{a_{i}, b_{i+1}\} + a_{i+1} + b_{i} \]

相同项移到同一边有

\[\max\{a_{i+1}, b_{i}\} - (a_{i+1} + b_{i}) \leq \max\{a_{i}, b_{i+1}\} - (a_{i} + b_{i+1}) \]

这等价于

\[\min\{a_{i+1}, b_{i}\} \geq \min\{a_{i}, b_{i+1}\} \]

于是我们就得到了最终式, 直接 sort 就好了.

......等会, 这 cmp() 函数怎么感觉有点奇怪呢, 这真的能成功按照我们的想法 sort 吗? 嘛, 事实是, sort 能跑, 但是结果不尽如人意. 这时候就需要引入 Strict Weak Ordering 这个东西了 ┏ (゜ ω ゜)=👉

Strict Weak Ordering[1]

简单来说, STL  的任何比较函数 (包括但不限于使用 std::sortstd::lower_boundstd::priority_queue 时重载的小于号), 都需要满足以下四个条件: (用  \(<\)  表示重载的运算符)

  1. \(x \not< x\) (非自反性)
  2. \(x < y\), 则 \(y \not< x\) (非对称性)
  3. \(x < y, y < z\), 则 \(x < z\) (传递性)
  4. \(x \not< y, y \not< z\), 则 \(x \not< z\) (不可比性的传递性)

事实上可以由 1 和 3 推出 2.

\(\min\{a_{i+1}, b_{i}\} \geq \min\{a_{i}, b_{i+1}\}\) 这个式子并不满足条件 4. 事实上, 去掉 \(=\) 是能够满足上述条件的, 但是此时就会犯一个邻项交换排序中经典的错误. \(\min\{a_{i+1}, b_{i}\} > \min\{a_{i}, b_{i+1}\}\) 仅仅是我们不交换相邻两项的必要条件, 而不是充要条件, 仔细思考就会发现, 这种错误同样出自于缺失「不可比性的传递性」, 也就是说, 邻项交换排序的条件式同样需要满足 Strict Weak Ordering.

虽然按条件判断相等的两组数交换一次对后面确实不会产生影响,但可以通过多次交换对最终结果产生影响。[2]

这时候应该怎么办? 不妨考虑一下多次交换造成最终影响的来源是什么. 在本题中, \(a\) 数组的排序可能会截断 \(\sum b\), 如果 \(c_{i}\) 表达式中取 \(\max\) 的是 \(c_{i-1}\), 它必然会有以 \(i-1\) 为结尾的某一段 \(b\) 数组的后缀和, 而之后若某一次 \(\sum_{i=1}^{k} a_{j}\) 取到了 \(\max\), 便会在最终结果中消去前面所有 \(b\) 数组的影响, 而无论谁取到了 \(\max\), \(a\) 数组在之前产生的影响一定不会被消除, 那么我们必然希望较大的 \(a_{i}\) 放在后面来提高取消目前存在的 \(b\) 数组的影响的概率, 同时也能让前面可能造成对 \(c\) 的影响的 \(a\) 尽可能小. 因此当 \(\min\{a_{i+1}, b_{i}\} = \min\{a_{i}, b_{i+1}\}\) 时, 我们修改判定条件为 \(a_{i} < a_{i+1}\), 可以发现此时的判定式是满足 STL 的 Strict Weak Ordering 条件的.

当然, 还有一种按 \(d_{i} = \frac{a_{i} - b_{i}}{\lvert a_{i} - b_{i} \rvert}\) 排序[3]的, 同样用到了 \(a\) 小放前面, \(b\) 大的放前面的贪心思路, 但是感觉做法没有前面的那么自然 qwq.

代码

#include <bits/stdc++.h>

using i64 = long long;
using PLL = std::pair<i64, i64>;

void solve() {
	int n;
	std::cin >> n;
	std::vector<PLL> pr(n);
	for (int i = 0; i < n; ++i) {
		std::cin >> pr[i].first >> pr[i].second;
	}

	std::sort(pr.begin(), pr.end(), [&](PLL x, PLL y) -> bool {
		i64 u = std::min(y.first, x.second), v = std::min(x.first, y.second);
		return u == v ? x.first > y.first : u > v;
	});

	i64 c = 0, s = 0;
	for (int i = 0; i < n; ++i) {
		s += pr[i].first;
		c = std::max(c, s) + pr[i].second;
	}

	std::cout << c << "\n";
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int T;
	std::cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

Further Reading


  1. 摘自 关于 P2123 【皇后游戏】错解的一些讨论以及一种不同的做法 - ouuan Part0 ↩︎

  2. 摘自 题解 P2123 【皇后游戏】- liuzibujian ↩︎

  3. 参考 题解 P2123 【皇后游戏】- TA123 ↩︎

posted @ 2024-11-26 14:31  小蒟蒻hlw  阅读(23)  评论(0)    收藏  举报