NKOJ 2139 鸡蛋染色

探讨了一种特殊染蛋分配问题,通过贪心算法快速找到最优解,确保两个孩子的报酬差额不超过500块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

比特兰人都很怪异,他们有一些奇怪的习俗。
为准备“比特兰狂欢节”,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) (1n106),表示总共有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=1inG。依次考虑每个鸡蛋,对于每个鸡蛋,可以让 a a a 涂它,也可以继续让 g g g 涂它。如果让 a a a 涂这个鸡蛋,那么 s s s 应该更新为 s − G i − A i s-G_i-A_i sGiAi,由于 A i + G i = 1000 A_i+G_i=1000 Ai+Gi=1000, 则 s = s − 1000 s=s-1000 s=s1000。如果继续让 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=1inG>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=1inG1000×n ,因此问题一定有解。

那对于每个鸡蛋,由于要求字典序最小,我们肯定希望尽量让 a a a 涂它。不管让 a a a 涂哪个鸡蛋, s s s 均减少 1000 1000 1000,所以当 s ≥ 500 s\geq 500 s500 时,我们肯定让 a a a 涂这个鸡蛋。因为当 s ≤ 500 s\leq 500 s500 时, ∣ s − 500 ∣ > 500 \vert s-500 \vert > 500 s500>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');
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值