P1080 [NOIP 2012 提高组] 国王游戏
通过这道题可以了解邻项排序类贪心题目的一般流程。
题意简述
有 n 个大臣和一个国王,每个大臣左、右手各有一个数,分别记为 ai,bi,国王手上也有数,记为 a,b。现在让国王排在队首,大臣按一定顺序排成一列接在国王后面。
每个大臣都会得到国王的金币奖励,对于队伍中排第 k(1≤k≤n)的大臣,他得到的金币
wk=bka∏i=1kak.
也就是他前面所有人(包括国王)左手上的数之积除以他自己右手上的数。现在希望通过恰当地安排大臣的排列顺序,使得 maxwk,即获得金币最多的大臣获得的金币数尽可能小。
这是一道经典的邻项排序问题,可以通过这道题学会邻项排序的基本思路。请注意下文中加粗的部分。
对于两个相邻的大臣,分别排在 i,j 位置上,假设 i<j,他们之前所有人左手上的数的乘积为 p。那么他们现在得到的金币数分别是:
wi=bip,wj=bjp×ai,
如果他们交换位置,那么有:
wi′=bip×aj,wj′=bjp.
现在我们考虑,如果要满足 i<j 时 max{wi,wj} 比 j<i 时更小(或相等),即
max{bip,bjp×ai}≤max{bip×aj,bjp},
应该满足什么条件? 我们考虑分类讨论,然后归纳:
-
首先有以下事实:
bip≤bip×aj,bjp×ai≥bjp.
-
由上述事实可知,当左侧 p/bi 成为最大值时,右侧一定 ≥ 左侧(因为右侧 ≥(p×aj)/bi)。为了让左侧 p/bi 成为最大值,需要满足:
bip≥bjp×ai⇒bj≥ai×bi.(1)
-
对于另一种情况,左侧 (p×ai)/bj 成为最大值时,考虑右侧情况:
为了让右侧 (p×aj)/bi 成为最大值,需要满足:
bip×aj≥bjp⇒aj×bj≥bi.(2)
但是这似乎没什么用,再想想能找到什么条件。我们还要让此时右侧最大值 ≥ 左侧最大值,即:
bip×aj≥bjp×ai⇒aj×bj≥ai×bi.(3)
我们得到了三个不等式,现在进行归纳。我们想要的终极约束不等式(∗)=(1)∪[(2)∩(3)].
所以有:
aj×bj≥ai×bi.(∗)
也就是说,只要相邻的两个大臣 i,j 满足这个条件,就让 i<j,即大臣 i 排在前面。
根据这个设计 bool operator<()
,然后用 std::sort()
就可以了。我们可以把国王和大臣的 a,b 统一存储于一个数组中,但是排序的时候从第二个元素开始排,这样写起来可以简单点。
这题要用高精度才能 AC。