[NOIP2012 提高组] 国王游戏
传送门
题目描述
恰逢 H 国国庆,国王邀请 n n n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n n n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入格式
第一行包含一个整数 n n n,表示大臣的人数。
第二行包含两个整数 a a a 和 b b b,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n n n 行,每行包含两个整数 a a a 和 b b b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
样例 #1
样例输入 #1
3
1 1
2 3
7 4
4 6
样例输出 #1
2
提示
【输入输出样例说明】
按 1 1 1、 2 2 2、 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;
按 1 1 1、 3 3 3、 2 2 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;
按 2 2 2、 1 1 1、 3 3 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;
按 2 2 2、 3 3 3、 1 1 1这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9;
按 3 3 3、 1 1 1、 2 2 2这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 2 2;
按 3 3 3、 2 2 2、 1 1 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 9 9。
因此,奖赏最多的大臣最少获得 2 2 2 个金币,答案输出 2 2 2。
【数据范围】
对于 20 % 20\% 20% 的数据,有 1 ≤ n ≤ 10 , 0 < a , b < 8 1≤ n≤ 10,0 < a,b < 8 1≤n≤10,0<a,b<8;
对于 40 % 40\% 40% 的数据,有 1 ≤ n ≤ 20 , 0 < a , b < 8 1≤ n≤20,0 < a,b < 8 1≤n≤20,0<a,b<8;
对于 60 % 60\% 60% 的数据,有 1 ≤ n ≤ 100 1≤ n≤100 1≤n≤100;
对于 60 % 60\% 60% 的数据,保证答案不超过 1 0 9 10^9 109;
对于 100 % 100\% 100% 的数据,有 1 ≤ n ≤ 1 , 000 , 0 < a , b < 10000 1 ≤ n ≤1,000,0 < a,b < 10000 1≤n≤1,000,0<a,b<10000。
NOIP 2012 提高组 第一天 第二题
解题思路
- 考虑对一合法大臣排列,交换i与j(i<j)的位置,就能获得更优解
- 设 A i A_i Ai= a 1 ⋅ a 2 ⋅ ... ⋅ a i a_1·a_2·...·a_i a1⋅a2⋅...⋅ai
- 交换前 A n s 1 = M a x ( A i − 1 / b i , A j − 1 / b j ) Ans1=Max(A_{i-1}/b_i,A_{j-1}/b_j) Ans1=Max(Ai−1/bi,Aj−1/bj)
- 交换后 A n s 2 = M a x ( A i − 1 / b j , A j − 1 ∗ a j / a i / b i ) Ans2=Max(A_{i-1}/b_j,A_{j-1}*a_j/a_i/b_i) Ans2=Max(Ai−1/bj,Aj−1∗aj/ai/bi)
- 需满足 A n s 1 > A n s 2 Ans1>Ans2 Ans1>Ans2才需交换
由 A i − 1 / b i < A j − 1 ∗ a j / a i / b i A_{i-1}/b_i < A_{j-1}*a_j/a_i/b_i Ai−1/bi<Aj−1∗aj/ai/bi; A j − 1 / b j > A i − 1 / b j A_{j-1}/b_j > A_{i-1}/b_j Aj−1/bj>Ai−1/bj,可知,若等式成立,则- 必然满足 A j − 1 / b j > A j − 1 ∗ a j / a i / b i A_{j-1}/b_j > A_{j-1}*a_j/a_i/b_i Aj−1/bj>Aj−1∗aj/ai/bi
- 即 a i ⋅ b i > a j ⋅ b j a_i·b_i>a_j·b_j ai⋅bi>aj⋅bj
- 以此排序即可获得最优排列顺序
(什么证完了?还不懂?戳我)
cpp
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 1000 + 5;
int n, A, B;
struct project {
int a, b;
} hands[Maxn];
int sum[Maxn], tmp[Maxn], p[Maxn], len2, len1, m, P;
inline bool cmp(project A, project B) {
if (A.a * A.b == B.a * B.b) {
return A.b < B.b;
}
return A.a * A.b < B.a * B.b;
}
inline bool Max() {
int i, j;
i = j = 1;
while (p[i] == 0 && i <= len2) {
i++;
}
while (tmp[j] == 0 && j <= len1) {
j++;
}
if (len2 - i + 1 > len1 - j + 1) {
return 0;
}
if (len2 - i + 1 < len1 - j + 1) {
return 1;
}
while (i <= len2 && j <= len1) {
if (p[i] < tmp[j]) {
return 1;
}
if (p[i] > tmp[j]) {
return 0;
}
i++;
j++;
}
return 0;
}
inline void mul(int d) {
for (int i = 1; i <= m; i++) {
sum[i] *= hands[d].a;
}
for (int i = 1; i <= m; i++) {
sum[i + 1] += sum[i] / 10000;
sum[i] %= 10000;
}
if (sum[m + 1] != 0) {
m++;
}
}
inline void div(int d) {
memset(tmp, 0, sizeof(tmp));
len1 = 1;
while (m > 0 && sum[m] == 0) {
m--;
}
P = 0;
bool flag = 0;
for (int i = m; i >= 1; i--) {
P = P * 10000 + sum[i];
tmp[++len1] = P / hands[d].b;
if (tmp[len1] == 0 && !flag) {
len1--;
} else {
flag = 1;
}
P %= hands[d].b;
}
}
inline void work() {
cin >> n >> A >> B;
for (int i = 1; i <= n; i++) {
cin >> hands[i].a >> hands[i].b;
}
sort(hands + 1, hands + n + 1, cmp);
m = 1;
sum[1] = A;
for (int i = 1; i <= n; i++) {
div(i);
if (Max()) {
len2 = len1;
memcpy(p, tmp, sizeof(tmp));
}
mul(i);
}
int i = 0;
while (i <= len2 && p[i] == 0) {
i++;
}
cout << p[i];
i++;
for (; i <= len2; i++) {
if (0 <= p[i] && p[i] <= 9) {
cout << "000" << p[i];
} else if (10 <= p[i] && p[i] <= 99) {
cout << "00" << p[i];
} else if (100 <= p[i] && p[i] <= 999) {
cout << "0" << p[i];
} else {
cout << p[i];
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
work();
return 0;
}
想要提升实力?看这里。