C/C++教程

算法刷题【洛谷P1080 & NOIP2012 提高组】国王游戏(附sort cmp函数使用警告)

本文主要是介绍算法刷题【洛谷P1080 & NOIP2012 提高组】国王游戏(附sort cmp函数使用警告),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

异想之旅:本人原创博客完全手敲,绝对非搬运,全网不可能有重复;本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告。本人所有文章仅在CSDN和个人博客(一定是异想之旅域名)发布,除此之外全部是盗文!


洛谷 P1080 国王游戏

题目描述

恰逢 $H 国 国 庆 , 国 王 邀 请 国国庆,国王邀请 国国庆,国王邀请 n$ 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n n n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式

第一行包含一个整数 n n n,表示大臣的人数。

第二行包含两个整数 a a a 和 b b b,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 n n n 行,每行包含两个整数 a a a 和 b b b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式

一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

输入输出样例

In 1:

3
1 1
2 3
7 4
4 6

Out 1:

2

由于本题特殊情况较多,这里多给出2个样例(分别为洛谷评测样例 #6 和 #7)方便调试

In 3:

100 70 94 43 9 92 18 18 9 86 31 24 32 46 49 23 69 40 56 27 75 28 85 37 29 99 80 44 70 14 9 30 38 46 32 93 87 42 49 35 60 99 73 57 8 38 35 73 33 6 32 10 36 78 75 49 98 50 48 91 78 18 3 86 24 18 84 27 28 83 25 15 95 38 18 50 89 79 9 3 17 1 52 74 32 76 99 24 36 9 43 93 7 65 27 36 84 75 31 94 44 33 2 85 5 42 18 4 33 45 84 92 87 86 34 36 44 61 59 59 28 1 97 60 23 9 64 96 47 57 100 90 7 54 93 17 30 71 23 72 32 14 95 48 40 27 15 92 78 52 11 93 21 56 60 22 47 21 58 89 11 29 13 36 14 95 91 47 12 16 36 19 80 19 92 73 68 66 1 53 97 13 60 83 5 63 99 98 37 2 67 84 95 26 60 63 33 2 78 91 38 9 31

Out 3:

2166489661101032350678866897536628698296804147316726878162441737980268621335310233327258927458239967674879428851028800069063620140885606400000000000000000

In 4:

100 1 1 1 1 2 1 2 2 1 2 1 2 2 2 1 2 1 2 2 2 2 2 1 2 2 1 1 2 1 2 1 2 1 2 2 2 1 2 1 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1 1 2 1 2 2 2 1 1 1 2 1 1 1 2 2 2 1 2 1 2 2 2 2 2 1 2 1 2 2 1 1 2 1 1 1 2 1 1 2 1 2 2 1 1 2 2 1 1 2 2 1 2 2 2 1 2 2 2 1 2 1 2 2 2 1 2 2 2 1 2 1 2 1 1 2 1 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 1 2 2 1 2 2 1 2 2 1 2 1 1 1 2 1 1 1 2 1 2 2 2 1 2 1 1 1 1 2 2 1 2 2 2 2 1 1 2 2 1 1 2 1 2 2 2 1 2 1 2 1 2 1 1 1 2

Out 4:

268435456

数据范围

对于 20%的数据,有 1 ≤ n ≤ 10 , 0 < a , b < 8 1≤ n≤ 10, 0 < a,b < 8 1≤n≤10,0<a,b<8;

对于 40%的数据,有 1 ≤ n ≤ 20 , 0 < a , b < 8 1≤ n≤20, 0 < a,b < 8 1≤n≤20,0<a,b<8;

对于 60%的数据,有 1 ≤ n ≤ 100 1≤ n≤100 1≤n≤100;

对于 60%的数据,保证答案不超过 1 0 9 10^9 109;

对于 100%的数据,有 1 ≤ n ≤ 1 × 1 0 3 , 0 < a , b < 1 × 1 0 4 1 ≤ n ≤1\times10^3, 0 < a,b < 1\times10^4 1≤n≤1×103,0<a,b<1×104。

题解

对于100%的数据,看 Out 3 样例中输出的数字就知道了,高精度逃不过……本题中需要自己实现高精度乘法、高精除以int除法、高精度数字大小比较等。同时,高精度操作来操作去对C++字符串操作的熟悉程度也有很高要求。

另外就是大家都可以想到的,计算前一定要排序,且一定是一个贪心算法。接下来就来推理贪心的公式:

  1. 设当前有两个紧靠着的大臣 i , i + 1 i,i+1 i,i+1 ,其中大臣 i i i 左手数字为 L i L_i Li​ ,右手数字为 R i R_i Ri​ ;同理大臣 i + 1 i+1 i+1 左手数字为 L i + 1 L_{i+1} Li+1​ ,右手数字为 R i + 1 R_{i+1} Ri+1​ 。在 0 0 0 到 i i i 之间的大臣(包括皇帝)左手数字乘积为 T T T 。
  2. 此时(交换前)大臣 i i i 获得的钱为 T R i \frac{T}{R_i} Ri​T​ ,大臣 i + 1 i+1 i+1 获得的钱为 T × L i R ( i + 1 ) \frac{T \times L_i}{R_{(i+1)}} R(i+1)​T×Li​​
  3. 交换两人位置,交换后大臣 i + 1 i+1 i+1 获得的钱为 T R ( i + 1 ) \frac{T}{R_{(i+1)}} R(i+1)​T​ ,大臣 i i i 获得的钱为 T × L ( i + 1 ) R i \frac{T \times L_{(i+1)}}{R_i} Ri​T×L(i+1)​​
  4. 由数据范围 0 < a , b < 1 × 1 0 4 0 < a,b < 1\times10^4 0<a,b<1×104 可知
    • 交换前大臣 i i i 的钱数 小于等于 交换后大臣 i i i 的钱数,即 T R i ≤ T × L ( i + 1 ) R i \frac{T}{R_i} ≤ \frac{T \times L_{(i+1)}}{R_i} Ri​T​≤Ri​T×L(i+1)​​ 恒成立,进而若最大值出现于交换前,则最大值为交换前大臣 i + 1 i+1 i+1 的钱数,即 m a x 1 = T × L i R ( i + 1 ) max_1=\frac{T \times L_i}{R_{(i+1)}} max1​=R(i+1)​T×Li​​
    • 交换前大臣 i + 1 i+1 i+1 的钱数 大于等于 交换后大臣 i + 1 i+1 i+1 的钱数,即 T × L i R ( i + 1 ) ≥ T R ( i + 1 ) \frac{T \times L_i}{R_{(i+1)}} ≥ \frac{T}{R_{(i+1)}} R(i+1)​T×Li​​≥R(i+1)​T​ 恒成立,进而若最大值出现于交换后,则最大值为交换后大臣 i i i 的钱数,即 m a x 2 = T × L ( i + 1 ) R i max_2=\frac{T \times L_{(i+1)}}{R_i} max2​=Ri​T×L(i+1)​​
  5. 由上方两条结论可知,若交换前最大值更小,换句话说就是当前大臣 i i i 和 i + 1 i+1 i+1 的排列顺序满足题目要求,则有 m a x 1 ≤ m a x 2 max_1 ≤ max_2 max1​≤max2​ ,即 T × L i R ( i + 1 ) ≤ T × L ( i + 1 ) R i \frac{T \times L_i}{R_{(i+1)}} ≤ \frac{T \times L_{(i+1)}}{R_i} R(i+1)​T×Li​​≤Ri​T×L(i+1)​​
  6. 对于上式,两边同除以 T T T ,再同乘 R i R ( i + 1 ) R_i R_{(i+1)} Ri​R(i+1)​ ,化简后得到 L i R i ≤ L ( i + 1 ) R ( i + 1 ) L_iR_i ≤ L_{(i+1)}R_{(i+1)} Li​Ri​≤L(i+1)​R(i+1)​ 。

证毕。

我敢说我比任何题解证得好

但是此处需要注意一件事!

就是题目中提到了的 sort cmp 函数使用警告——cmp函数的比较符必须是开区间!具体见下面这个例子

bool cmp(int a, int b) {
	// 错误
	// return a >= b;
	// 正确
	return a > b;
}

使用闭区间,否则Windows会莫名退出,Linux显示错误信息 Segmentation fault 外无更多提示。

如果想要研究原理,可以看看这两个文章(蒟蒻看不懂):

  • C++ sort之Segmentation fault原因及其解决方法_-绿色小屋-CSDN博客
  • C++ Sort Segmentation Fault | BiaSee
这篇关于算法刷题【洛谷P1080 & NOIP2012 提高组】国王游戏(附sort cmp函数使用警告)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!