NOIP2012提高
国王游戏
恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。
首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。
然后,让这 n 位大臣排成一排,国王站在队伍的最前面。
排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:
排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。
注意,国王的位置始终在队伍的最前面。
输入格式
第一行包含一个整数 n,表示大臣的人数。
第二行包含两个整数 a 和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
数据范围
1≤n≤10001≤n≤1000
0<a,b<100000<a,b<10000
输入样例:
3
1 1
2 3
7 4
4 6
输出样例:
2
+++
贪心的策略是将大臣按照左右手数字相乘的数字排序,严格证明后可知这样为最优排列。
因为本题数据较大,要涉及高精度,所以要用到高精度乘法和除法。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
PII a[N];
int n;
vector<int> mul(vector<int> A, int b)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size() || t; i ++ )
{
if(i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while(C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
vector<int> div(vector<int> a, int b)
{
vector<int> c;
for (int i = a.size() - 1, t = 0; i >= 0; i -- )
{
t = t * 10 + a[i];
c.push_back(t / b);
t %= b;
}
reverse(c.begin(), c.end());
while(c.size() > 1 && c.back() == 0) c.pop_back();
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()
{
scanf("%d", &n);
int p, q;
for (int i = 0; i <= n; i ++ )
{
scanf("%d%d", &p, &q);
a[i] = {p * q, p};
}
sort(a + 1, a + n + 1);
vector<int> Now(1, 1);
vector<int> ans(1, 0);
for (int i = 0; i <= n; i ++ )
{
if(i) ans = max_vec(ans, div(Now, a[i].first / a[i]. second));
Now = mul(Now, a[i].second);
}
for (int i = ans.size() - 1; i >= 0; i -- ) cout << ans[i];
cout << endl;
return 0;
}