题目描述:
恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入格式
第一行包含一个整数 n,表示大臣的人数。第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
数据范围
1≤n≤1000
0<a,b<10000
输入样例:
3
1 1
2 3
7 4
4 6
输出样例:
2
分析:
本题考查贪心+高精度。
贪心部分
设大臣们排成的队列为...A,B...。且A之前的人左手数的乘积为x。A左手的数是l1,右手的数是r1;B左手的数是l2,右手的数是r2。则此时A可以获得的金币数是x / r1,B可以获得的金币数是x * l1 / r2.如果交换A,B的位置,得到...B,A...,那么此时A可以得到的金币数是x * l2 / r1,B可以得到的金币数是x / r2。交换前,二者当中能得到最多的金币数是max{x / r1,x * l1 / r2},交换后能得到的最多金币数是max{x * l2 / r1,x / r2}。为了方便比较,不妨对各个部分都乘以r1 * r2 / x。得到左边=max{r2,l1 * r1}和右边=max{l2 * r2,r1},由于大臣手中的数都是正整数,有r1 <=l1 * r1;r2 <= l2 * r2。所以l1 * r1 <= l2 * r2时,右边更大,即前面大臣左右手数乘积小于后面大臣左右手乘积时,交换他们会导致他们中获得的金币最大的那个人获得的金币增加,所以得出结论:按照l * r排序的话,减小逆序对的数量会使得整体获得的最大金币数不会增加。于是根据贪心的思想,按照l * r对大臣们进行排序,找出他们当中获得金币的最大数即是解。虽然贪心部分原来看起来多,实际上相当简单,只是实现二十来行代码即可解决。但是本题比贪心策略复杂的是高精度。最大数接近1000个10000相乘,这是一个特别大的数,超出了所有数据类型的表示范围。
高精度部分
高精度部分主要实现大数的乘法,除法,比较以及输出。采用vector存储大数的每个位。
乘法:主要是从低位到高位每个位都乘以乘数,得到的结果个位存进结果,其他位当做结果进入下一轮,不要忘记将最后的进位数同样存入结果向量。
乘法:从高位向低位每加上一位判断能不能除掉除数,并且将每轮的商存入结果向量,将余数乘10加到下一轮除法中。注意商前面的零不要存储,而后面的零需要存储。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
const int maxn = 1010;
int n;
PII p[maxn];
vector<int> mul(vector<int> a,int b){//乘法
vector<int> c;//存放结果
int t = 0;//存放进位
for(int i = 0;i < a.size();i++){
t += a[i] * b;
c.push_back(t % 10);
t /= 10;
}
while(t){
c.push_back(t % 10);
t /= 10;
}
return c;
}
vector<int> div(vector<int> a,int b){//除法
vector<int> c;
bool pre = true;
for(int i = a.size() - 1,t = 0;i >= 0;i--){
t = t * 10 + a[i];
int x = t / b;
if(!pre || x){//不要前缀零,而要保留后缀零
pre = false;
c.push_back(x);
}
t %= b;
}
reverse(c.begin(),c.end());
return c;
}
vector<int> max_vec(vector<int> a,vector<int> b){//比较
if(a.size() > b.size()) return a;
if(a.size() < b.size()) return b;
if(vector<int>(a.rbegin(),a.rend()) > vector<int>(b.rbegin(),b.rend())) return a;
return b;
}
int main(){
cin>>n;
for(int i = 0;i <= n;i++){
int a,b;
cin>>a>>b;
p[i] = {a * b,a};
}
sort(p + 1,p + n + 1);
vector<int> pro(1,1),res(1,0);
for(int i = 0;i <= n;i++){
if(i) res = max_vec(res,div(pro,p[i].first / p[i].second));
pro = mul(pro,p[i].second);
}
for(int i = res.size() - 1;i >= 0;i--) cout<<res[i];
cout<<endl;
return 0;
}