贪心 + 排序
题目描述
在蓝桥王国中,有
n
n
n 名士兵,这些士兵需要接受一系列特殊的训练,以提升他们的战斗技能。对于第
i
i
i 名士兵来说,进行一次训练所需的成本为
p
i
p_i
pi 枚金币,而要想成为顶尖战士,他至少需要进行
c
i
c_i
ci 次训练。
为了确保训练的高效性,王国推出了一种组团训练的方案。该方案包含每位士兵所需的一次训练,且总共只需支付
S
S
S 枚金币(组团训练方案可以多次购买,即士兵可以进行多次组团训练)。
作为训练指挥官,请你计算出最少需要花费多少金币,才能使得所有的士兵都成为顶尖战士?
输入格式
输入的第一行包含两个整数
n
n
n 和 $S $,用一个空格分隔,表示士兵的数量和进行一次组团训练所需的金币数。
接下来的
n
n
n 行,每行包含两个整数
p
i
p_i
pi 和
c
i
c_i
ci,用一个空格分隔,表示第
i
i
i 名士兵进行一次训练的金币成本和要成为顶尖战士所需的训练次数。
输出格式
输出一行包含一个整数,表示使所有士兵成为顶尖战士所需的最少金币数。
输入输出样例 #1
输入 #1
3 6
5 2
2 4
3 2
输出 #1
16
说明/提示
花费金币最少的训练方式为:进行 2 2 2 次组团训练,花费 2 × 6 = 12 2 × 6 = 12 2×6=12 枚金币,此时士兵 1 , 3 1, 3 1,3 已成为顶尖战士;再花费 4 4 4 枚金币,让士兵 2 2 2 进行两次训练,成为顶尖战士。总花费为 12 + 4 = 16 12 + 4 = 16 12+4=16。
对于 40 % 40\% 40% 的评测用例, 1 ≤ n ≤ 1 0 3 , 1 ≤ p i , c i ≤ 1 0 5 , 1 ≤ S ≤ 1 0 7 1 ≤ n ≤ 10^3,1 ≤ p_i , c_i ≤ 10^5,1 ≤ S ≤ 10^7 1≤n≤103,1≤pi,ci≤105,1≤S≤107。
对于所有评测用例, 1 ≤ n ≤ 1 0 5 , 1 ≤ p i , c i ≤ 1 0 6 , 1 ≤ S ≤ 1 0 10 1 ≤ n ≤ 10^5,1 ≤ p_i , c_i ≤ 10^6,1 ≤ S ≤ 10^{10} 1≤n≤105,1≤pi,ci≤106,1≤S≤1010。
思路:
- nums数组表示士兵的训练所需金额 及 次数,n表示士兵的个数,S表示团购价格,res存放花费的金币,cnt表示当前使用团购的次数
- nums已排序好按照训练次数倒序排列好,以便我们训练完该士兵后pop,当士兵全部训练完时退出循环
- 流程:先将一个士兵训练好,记录好购买的团购次数cnt,然后下一个士兵来时用团购次数抵消,在我们团购的时候需要将团购次数cnt更新为c,而单独训练士兵时不用
代码示例:
import sys
input = lambda: sys.stdin.readline().strip() # noqa: E731
n, S = map(int, input().split())
nums = [list(map(int, input().split())) for _ in range(n)]
nums.sort(key=lambda x: x[1], reverse=True)
cnt, res = 0, 0
money = sum(p for p, c in nums) # 维护剩余人数训练一次的金额
while nums:
# 团购 or 单独训练
# 如果剩余人数的训练一次的总金额的和大于s 则团购,反之单独训练
p, c = nums.pop()
if money > S:
# 团购
res += S * (c - cnt)
cnt = c # 更新团购次数
else:
# 单独训练
res += p * (c - cnt)
money -= p
print(res)