洛谷P1080 国王游戏

洛谷 P1080 国王游戏

题目描述

恰逢 HH国国庆,国王邀请nn 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 nn 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。

国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

输入格式

第一行包含一个整数nn,表示大臣的人数。

第二行包含两个整数 aa和 bb,之间用一个空格隔开,分别表示国王左手和右手上的整数。

接下来 nn行,每行包含两个整数aa 和 bb,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。

输出格式

一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

输入输出样例

输入 #1复制

1
2
3
4
5
3 
1 1
2 3
7 4
4 6

输出 #1复制

1
2

说明/提示

【输入输出样例说明】

按11、22、33 这样排列队伍,获得奖赏最多的大臣所获得金币数为 22;

按 11、33、22 这样排列队伍,获得奖赏最多的大臣所获得金币数为22;

按 22、11、33 这样排列队伍,获得奖赏最多的大臣所获得金币数为 22;

按22、33、11这样排列队伍,获得奖赏最多的大臣所获得金币数为99;

按 33、11、22这样排列队伍,获得奖赏最多的大臣所获得金币数为 22;

按33、22、11 这样排列队伍,获得奖赏最多的大臣所获得金币数为 99。

因此,奖赏最多的大臣最少获得 22个金币,答案输出 22。

【数据范围】

对于 20%的数据,有 1≤ n≤ 10,0 < a,b < 81≤n≤10,0<a,b<8;

对于 40%的数据,有1≤ n≤20,0 < a,b < 81≤n≤20,0<a,b<8;

对于 60%的数据,有 1≤ n≤1001≤n≤100;

对于 60%的数据,保证答案不超过 10^9109;

对于 100%的数据,有 1 ≤ n ≤1,000,0 < a,b < 100001≤n≤1,000,0<a,b<10000。

NOIP 2012 提高组 第一天 第二题


题解来自https://www.luogu.com.cn/blog/league/solution-p1080

主要就是贪心,在队伍前面依次插入一个最优的。但是这个最优的是什么?怎么证明?我属实想不明白,看了这篇题解懂的。这边偷一下:

(不得不感叹大佬的强大)

最后只要用一个高精度乘法和除法就可以判断答案了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <algorithm>
using namespace std;

struct minister
{
int left, right;
long long total;
bool operator < (minister const &temp) const
{
return this->total < temp.total;
}
};

struct bigN
{
int d[10000] = {0};
int len = 0;
bool operator < (bigN const &temp) const
{
if(this->len != temp.len)
return this->len < temp.len;
else
for(int i = this->len - 1; i >= 0; i--)
if(this->d[i] != temp.d[i])
return this->d[i] < temp.d[i];
}
};

bigN mult(bigN a, int b);
bigN divid(bigN a, int b);
void printN(bigN a);

int main(int argc, const char *argv[])
{
int N;
cin >> N;
minister M[N + 1];
M[0].left = M[0].right = M[0].total = 1;
for(int i = 0; i <= N; i++)
{
cin >> M[i].left >> M[i].right;
M[i].total = M[i].left * M[i].right;
}
sort(M + 1, M + N + 1);

bigN MAX, tot;
tot.len = 1; tot.d[0] = 1;
for(int i = 1; i <= N; i++)
{
tot = mult(tot, M[i - 1].left);
bigN temp = divid(tot, M[i].right);
if(MAX < temp)
MAX = temp;
}

printN(MAX);

return 0;
}

bigN mult(bigN a, int b)
{
bigN res;
int carry = 0;
for(int i = 0; i < a.len; i++)
{
int temp = a.d[i] * b + carry;
res.d[res.len++] = temp % 10;
carry = temp / 10;
}
while(carry)
{
res.d[res.len++] = carry % 10;
carry /= 10;
}

return res;
}

bigN divid(bigN a, int b)
{
bigN res;
res.len = a.len;
int r = 0;
for(int i = a.len - 1; i >= 0; i--)
{
r = r * 10 + a.d[i];
if(r < b)
res.d[i] = 0;
else
{
res.d[i] = r / b;
r = r % b;
}
}
while(res.len > 1 && res.d[res.len - 1] == 0)
res.len--;

return res;
}

void printN(bigN a)
{
for(int i = a.len - 1; i >= 0; i--)
cout << a.d[i];
cout << endl;
}

要注意的是,进行判断时上一步的乘法结果可以直接拿来用,不然就是O(n^2)的时间复杂度,后面几个测试点全部TLE,我就踩了这个坑,还一直没想到,感觉最近水平下降的有点严重,是要反思反思了。

作者

Jhuoer Yen

发布于

2021-04-07

更新于

2023-09-18

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×