在洛谷做的第一道“提高+/省选-”的题目,纪念一下(OTL)。
原题链接:https://www.luogu.org/problem/P1080
P1080 国王游戏
题目描述
恰逢H国国庆,国王邀请n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入格式
第一行包含一个整数n,表示大臣的人数。
第二行包含两个整数 a和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n行,每行包含两个整数a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
输入输出样例
输入 #1:
3
1 1
2 3
7 4
4 6
输出 #1:
2
说明/提示
【输入输出样例说明】
按1 11、222、333 这样排列队伍,获得奖赏最多的大臣所获得金币数为 222;
按 111、333、222 这样排列队伍,获得奖赏最多的大臣所获得金币数为2 22;
按 222、111、333 这样排列队伍,获得奖赏最多的大臣所获得金币数为 222;
按2 22、333、11 1这样排列队伍,获得奖赏最多的大臣所获得金币数为9 99;
按 333、111、22 2这样排列队伍,获得奖赏最多的大臣所获得金币数为 222;
按3 33、222、111 这样排列队伍,获得奖赏最多的大臣所获得金币数为 999。
因此,奖赏最多的大臣最少获得 22 2个金币,答案输出 222。
数据范围
对于 60%的数据,有 1≤n≤1001≤ n≤1001≤n≤100;
对于 60%的数据,保证答案不超过 10^9;
首先我们看到题目要求的是——使大臣们获得的奖赏尽可能的少,通常看到这一类的问题,我们第一时间应该想到的都是贪心或者DP,当然这道题也不例外。
那么,这里我们用贪心来解决(太菜了不会找动态转移方程,能不DP绝不DP,OTL),于是最重要的就是找到贪心策略了:
首先我们来看一看题目,题目要求求出在大臣们所得的奖赏最少的情况下的获赏最多的大臣获得的钱(国王脑子有坑(确信)),那么,根据这里和计算赏金的方法,我们首先可以确定的就是结果和大臣手上的数字(l,r)有关(迫真废话),具体什么关系,需要进一步推算。
假设一下,只有国王(L,R),大臣①(l1,r1),大臣(l2,r2) ,
于是我们得到了这样的初始序列:
(L,R) (l1,r1) (l2,r2)
因为国王是固定站在队首的,因此我们只需考虑两个大臣的站位,于是我们可以得到两种不同结果:
ans1 = max( L / r1 , L · l1 / r2 )
ans2 = max( L / r2 , L · l2 / r1 )
那么,到底哪个结果更小呢?不得而知,所以我们先令:
① = L / r1
② = L · l1 / r2
③ = L / r2
④ = L · l2 / r1
很显然,② > ③、④ > ①,
即:
L · l1 / r2 > L / r2
L · l2 / r1 > L / r1
那么再来假设一下,设ans1 < ans2,
于是我们得到了:
max( L / r1 , L · l1 / r2 ) < max( L / r2 , L · l2 / r1 )
即 max(①,②) < max(③,④)
那么很显然 ,我们可以得到:
max(③,④) = ④ = L · l2 / r1
于是就有,② < ④,即:
L · l1 / r2 < L · l2 / r1
→ l1 / r2 < l2 / r1
→ l1 · r1 < l2 · r2
这样一来,(l,r)对于最终赏金的影响我们就得到了,即l * r 的值越小的排在越前面,最终赏金就会越小
得到了贪心策略之后问题就好解决了——按照 l * r 的值进行一遍升序排序,即可得到答案了
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
Inputreader sc = new Inputreader();
int n = sc.nextInt();
int a = sc.nextInt();
int b = sc.nextInt();
peo t[] = new peo [n];
BigInteger temp = BigInteger.valueOf(a);
for(int i = 0;i < n;i++){
t[i] = new peo();
t[i].a = sc.nextInt();
t[i].b = sc.nextInt();
}
Arrays.sort(t,new cmp());
for(int i = 0;i < n-1;i++)
temp = temp.multiply(BigInteger.valueOf(t[i].a));
if(temp.compareTo(BigInteger.valueOf(t[n-1].b)) == -1)System.out.println(1);
else System.out.println(temp.divide(BigInteger.valueOf(t[n-1].b)));
}
}
class cmp implements Comparator<peo>{
public int compare(peo o1, peo o2) {
if(o1.a*o1.b<o2.a*o2.b)return-1;
else return 1;
}
}
class peo{
long a;
long b;
}
class Inputreader
{
BufferedReader buf;
StringTokenizer tok;
Inputreader()
{
buf = new BufferedReader(new InputStreamReader(System.in));
}
boolean hasNext()
{
while(tok == null || !tok.hasMoreElements())
{
try
{
tok = new StringTokenizer(buf.readLine());
}
catch(Exception e)
{
return false;
}
}
return true;
}
String next()
{
if(hasNext()) return tok.nextToken();
return null;
}
int nextInt()
{
return Integer.parseInt(next());
}
long nextLong()
{
return Long.parseLong(next());
}
double nextDouble()
{
return Double.parseDouble(next());
}
BigInteger nextBigInteger()
{
return new BigInteger(next());
}
BigDecimal nextBigDecimal()
{
return new BigDecimal(next());
}
}