问题描述:
比特兰人都很怪异,他们有一些奇怪的习俗。
为准备“比特兰狂欢节”,J叔叔让G和A去把n个鸡蛋染成彩色。孩子们很高兴,因为他们可以得到一些报酬。
J叔叔要他们给出酬劳的报价,G给出了染每只鸡蛋的价格,A也给出了他染每只鸡蛋的价格,结果G和A的n只鸡蛋报价总和恰好是1000块。
J叔叔想把这些鸡蛋分给两个孩子染色,但他希望支付给A的酬劳总额与支付给G的总额差别不超过500块。
请问J叔叔期望的分配方案是否可行呢?
输入格式:
第一行,一个整数
n
n
n
(
1
≤
n
≤
1
0
6
)
(1\leq n\leq 10^6)
(1≤n≤106),表示总共有n只鸡蛋
接下来n行,每行两个整数ai 和 gi (0 ≤ ai, gi ≤ 1000; ai + gi = 1000),ai表示A对第i只鸡蛋的报价,gi表示G对第i只鸡蛋的报价
若有多个方案,输出字典序最小的一种。
输出格式:
如果找不到可行的方案,输出-1
否则打印出分配的方案:一行,n个字母,依次对应n只鸡蛋的涂色者,若第i只鸡蛋是A涂的,打印"A",否则打印"G"
样例输入
样例1:
2
1 999
999 1
样例2:
3
400 600
400 600
400 600
样例输出
样例1:
AG
样例2:
AAG
首先纠正一点,“结果G和A的n只鸡蛋报价总和恰好是1000块。”意思是对于任意的
i
i
i ,
A
i
+
G
i
=
1000
A_i+G_i=1000
Ai+Gi=1000
.
这道题看上去挺吓人的,一百万的数据范围,但是其实这是一道贪心水题,连数组都不用。
我们先让
g
g
g 涂全部鸡蛋(这是为了后面的字典序最小),
s
s
s 表示当前
g
g
g 比
a
a
a 多得
s
s
s 块报酬。
则一开始
s
=
∑
i
=
1
i
≤
n
G
s=\sum_{i=1}^{i\leq n} G
s=∑i=1i≤nG。依次考虑每个鸡蛋,对于每个鸡蛋,可以让
a
a
a 涂它,也可以继续让
g
g
g 涂它。如果让
a
a
a 涂这个鸡蛋,那么
s
s
s 应该更新为
s
−
G
i
−
A
i
s-G_i-A_i
s−Gi−Ai,由于
A
i
+
G
i
=
1000
A_i+G_i=1000
Ai+Gi=1000, 则
s
=
s
−
1000
s=s-1000
s=s−1000。如果继续让
g
g
g 涂这个鸡蛋显然
s
s
s 不变。
那么, 只有当 ∑ i = 1 i ≤ n G > n × 1000 + 500 \sum_{i=1}^{i\leq n} G>n\times 1000+500 ∑i=1i≤nG>n×1000+500 时,问题无解。而由于 G i < 1000 G_i < 1000 Gi<1000 ,则 ∑ i = 1 i ≤ n G ≤ 1000 × n \sum_{i=1}^{i\leq n} G \leq 1000\times n ∑i=1i≤nG≤1000×n ,因此问题一定有解。
那对于每个鸡蛋,由于要求字典序最小,我们肯定希望尽量让 a a a 涂它。不管让 a a a 涂哪个鸡蛋, s s s 均减少 1000 1000 1000,所以当 s ≥ 500 s\geq 500 s≥500 时,我们肯定让 a a a 涂这个鸡蛋。因为当 s ≤ 500 s\leq 500 s≤500 时, ∣ s − 500 ∣ > 500 \vert s-500 \vert > 500 ∣s−500∣>500了,不能再继续让 a a a 涂鸡蛋了(他的工钱已经够多了)。
所以我们可以在输入后忽略 A i A_i Ai 和 G i G_i Gi,达到 O ( 1 ) O(1) O(1) 的空间复杂度。你没看错,代码只有9行。
C o d e : Code: Code:
#include <cstdio>
int main() {
int n, a, g, s(0);
scanf("%d", &n);
for (int i(1); i <= n; ++ i)
scanf("%d%d", &a, &g), s += g;
for (int i(1); i <= n; ++ i) if (s >= 500) s -= 1000, putchar('A');
else putchar('G');
}