114. 国王游戏
题目链接
114. 国王游戏
恰逢 \(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
解题思路
贪心,高精度
贪心策略:最终顺序为大臣左右数乘积的排序
证明(摘自蓝书):考虑交换邻项带来的影响:
对于任意一种顺序, 设 \(n\) 名大臣左、右手上的数分别是 \(A[1] \sim A[n]\) 与 \(B[1] \sim B[n]\), 国王手里的数是 \(A[0]\) 和 \(B[0]\) 。
如果我们交换两个相邻的大臣 \(i\) 与 \(i+1\), 在交换前这两个大臣获得的奖励是:
交换之后这两个大臣获得的奖励是:
其他大臣获得的奖励显然都不变, 因此我们只需要比较上面两组式子最大值的变 化。提取公因式 \(\prod_{j=0}^{i-1} A[j]\) 后, 实际上需要比较下面两个式子的大小关系:
两边同时乘上 \(B[i] * B[i+1]\), 变为比较:
注意到大臣手上的数都是正整数, 故 \(B[i+1] \leq A[i+1] * B[i+1]\), 且 \(A[i] *\) \(B[i] \geq B[i]\) 。
于是, 当 \(A[i] * B[i] \leq A[i+1] * B[i+1]\) 时, 左式 \(\leq\) 右式, 交换前更优。当 \(A[i] *\) \(B[i] \geq A[i+1] * B[i+1]\) 时, 左式 \(\geq\) 右式, 交换后更优。也就是说, 在任何局面下, 减小逆序对数都不会造成整体结果变差, 而增加逆序对数则不会使整体结果变好。
最后, 根据冒泡排序的知识, 任何一个序列都能通过邻项交换的方式变为有序序 列。故当逆序对数为 0 , 即按上述方案排序时就是最优策略。
最后注意需用高精度
- 时间复杂度:\(O(n^2)\)
代码
// Problem: 国王游戏
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/116/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
// #define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005;
int n;
vector<int> res(1,0),A(1,1);
PII x[N];
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.pb(t%10);
t/=10;
}
while(t)C.pb(t%10),t/=10;
return C;
}
vector<int> div(vector<int> A,int b)
{
vector<int> C;
int t=0;
bool f=false;
for(int i=A.size()-1;~i;i--)
{
t=t*10+A[i];
int m=t/b;
if(m||f)
{
f=true;
C.pb(m);
}
t%=b;
}
return vector<int>(C.rbegin(),C.rend());
}
vector<int> Max(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 B;
return A;
}
void out(vector<int> res)
{
for(int i=res.size()-1;~i;i--)
cout<<res[i];
puts("");
}
int main()
{
cin>>n;
for(int i=0;i<=n;i++)
{
cin>>x[i].fi>>x[i].se;
x[i]={x[i].fi*x[i].se,x[i].fi};
}
sort(x+1,x+1+n);
for(int i=0;i<=n;i++)
{
if(i)
res=Max(res,div(A,x[i].fi/x[i].se));
A=mul(A,x[i].se);
}
out(res);
return 0;
}