[Python] P10387 [蓝桥杯 2024 省 A] 训练士兵

贪心 + 排序

题目描述

在蓝桥王国中,有 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 1n1031pi,ci1051S107

对于所有评测用例, 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} 1n1051pi,ci1061S1010

思路:

  1. nums数组表示士兵的训练所需金额 及 次数,n表示士兵的个数,S表示团购价格,res存放花费的金币,cnt表示当前使用团购的次数
  2. nums已排序好按照训练次数倒序排列好,以便我们训练完该士兵后pop,当士兵全部训练完时退出循环
  3. 流程:先将一个士兵训练好,记录好购买的团购次数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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值