-
题目描述
恰逢 H 国国庆,国王邀请 t 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 t 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:「排在该大臣前面的所有人的左手上的数的乘积」除以「他自己右手上的数」,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入
第一行包含一个整数 t,表示大臣的人数。
第二行包含两个整数 n 和 m,n,m之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来t 行,每行包含两个整数 x 和 y,x,y之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
样例输入
3
1 1
2 3
7 4
4 6
样例输出
2
提示
- 按 1、2、3 号大臣这样排列队伍,获得奖赏最多的大臣所获得金币数为2 ;
按 1、3、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为2 ;
按 2、1、3 这样排列队伍,获得奖赏最多的大臣所获得金币数为2;
按 2、3、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9;
按 3、1、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 3、2、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为9 。
因此,奖赏最多的大臣最少获得 2个金币,答案输出2 。
-
贪心
本题为贪心题目,大家可以先在网上查阅贪心相关内容,这里仅做简单介绍。
贪心是一种在每次决策时采取当前意义下最优策略的算法,使用贪心法要求问题的整体最优性可以由局部最优性导出。贪心算法的正确使用需要证明,常见手法有:1.微扰 2.范围缩放 3.决策包容性 4.反证法 5.数学归纳法。
有《算法进阶竞赛指南》可以查阅本书第45页。
-
解题思路
在读题,并经过实际操作后,数据的处理是这样的(国王的右手无用,最后一位大臣的左手无用)即最后一个大臣得到的金币为1*2*7/6=2。
按照每个大臣左、右手上的数的乘积从小到大排序,就是最优排队方案。这个贪心算法,可以使用微扰法证明。
对于任意一种顺序,设n名大臣左、右手上的数分别是A[1]~A[n]与B[1]~B[n],国王手里的数是A[0]和B[0]。
如果我们交换相邻的两个大臣i与i+1,交换前这两个大臣得到的金币分别是:
与
交换之后这两个大臣获得的奖励是:
与
-
参考答案
#include <bits/stdc++.h>
#define int long long
//将int定义更改为long long
#define x first
#define y second
using namespace std;
typedef pair<int,int>pii;
//将pair<int,int>更名为pii
//typedef可以更改很多,可以自行查阅
const int N=1010;
pii p[N];
//由于int已被修改为long long
//应用signed定义main函数返回类型
signed main()
{
int n;
cin>>n;
for(int i=0;i<=n;i++)
{
int a,b;
cin>>a>>b;
//使得p[].x中存储a*b即大臣左右手乘积
p[i].x=a*b,p[i].y=a;
}
//快排(按照pair结构中第一个出现的数,由小到大排序)
sort(p+1,p+n+1);
int res=0,ans=1;
for(int i=0;i<=n;i++)
{ //在计算乘积之前应注意的是,p[].x存储了左右手乘积,每次运算应首先除以该大臣右手
if(i) res=max(res,ans/(p[i].x/p[i].y));
ans=ans*p[i].y;
}
cout<<res<<endl;
return 0;
}