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\)
如果我們交換兩個相鄰的大臣 \(i\) 與 \(i+1\), 在交換前這兩個大臣獲得的獎勵是: \[\frac{1}{B[i]} * \prod_{j=0}^{i-1} A[j] 與 \frac{1}{B[i+1]} * \prod_{j=0}^{i} A[j] \]
交換之後這兩個大臣獲得的獎勵是:
\[\frac{1}{B[i+1]} * \prod_{j=0}^{i-1} A[j] \text { 與 } \frac{A[i+1]}{B[i]} * \prod_{j=0}^{i-1} A[j] \]其他大臣獲得的獎勵顯然都不變, 因此我們只需要比較上面兩組式子最大值的變 化。提取公因式 \(\prod_{j=0}^{i-1} A[j]\)
兩邊同時乘上 \(B[i] * B[i+1]\), 變為比較:
\[\max (B[i+1], A[i] * B[i]) \quad \max (B[i], A[i+1] * 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;
}