运行要求
运行时间限制: 2sec
内存限制: 1024MB
原文连接算法
题目
现有N张卡片,每张卡片上面写有 整数Ai。如今你对j=1,2,3...M每次进行1次操做。
操做:选择最多Bj枚的卡片(0枚也能够)。把选择的卡片,换成Cj。
求通过M次操做之后,N枚卡片上面写的整数的求和值的最大值。数组
输入前提条件微信
输入
输入都以如下标准从命令行输入app
N M A1 A2 A3 ... An B1 C1 B2 C2 . . . BM CM
输出优化
M回操做之后,N枚卡片里整数合值的最大值
例1
输入spa
3 2 5 1 4 2 3 1 5
输出命令行
14
第1次操做不作操做,第2次操做把1换成5,这样最后的和是5+5+4=14
这个值是最大值code
例2
输入blog
10 3 1 8 5 7 100 4 52 33 13 5 3 10 4 30 1 4
输出排序
338
例3
输入
3 2 100 100 100 3 99 3 99
输出
300
例4
输入
11 3 1 1 1 1 1 1 1 1 1 1 1 3 1000000000 4 1000000000 3 1000000000
输出
10000000001
注意存在最后的结果不能被32比特容纳的状况
读懂题目
这一题能够当作,有一组纸牌ARR,针对这组纸牌能够进行M次的操做。
每次操做有面值为C的纸牌B张,在ARR纸牌里面能够挑一些很少余C张的纸牌,把它们换成面值为C的纸牌
解题思路
思路1: 刚开始的想法就是先对原始纸牌ARR作一个排序,由小到大。而后在对全部操做作一个排序,面值由大到小,再用面值大的操做去替换面值小的原始纸牌。而后若是想替换原始纸牌ARR里面没有比操做里纸牌的面值要小的话,中止替换。的这个思路是能够的,可是考虑到要对两组10^5的数组分别作排序,时间上是来不及的
思路2: 1<=Bi<=N有这么一个条件,也就是说,全部操做里面的牌的数量都是要小于原始纸牌ARR里面的纸牌的数量的。
操做里的全部的牌,均可以进入原始牌堆ARR
咱们要求最大的和,那么操做里面的大牌确定要进入原始牌堆ARR
那么咱们把操做的牌和原始牌堆ARR融合在一块儿作一个排序就行了,最后取最大的N张牌
可是这个操做要把两组10^5的数组融在一块儿排序,也就是说,最多要对2*10^5长度的数组排序,时间上也是不容许的。
思路3: 思路2里咱们是把操做牌里全部的牌都融合在了原始牌堆ARR里。可是咱们排序找最大的那几张牌其实关心的是操做牌的面值而不是操做牌的张数。这里咱们把思路2的算法优化一下。原始牌堆ARR里面的每张牌张数为1,操做牌里面的每张牌的张数为相应的值。咱们对面值作一个排序,而后一次从上往下取牌,知道取到了N张牌。
咱们假设输入是如下
3 2 5 1 4 2 3 3 5
那么操做牌堆里,5有3张,3有2张。按照面值排序,而后再取面值前3位的的牌求和。获得结果是15
代码
这里我只贴上思路3的代码
N,M = map(int,input().split()) ARR = list(map(int,input().split())) BRR = [] for i in range(M): BRR.append(list(map(int,input().split()))) def calculate(n, m, arr, brr): raw = [] for ar in arr: raw.append([ar, 1]) for br in brr: raw.append([br[1], br[0]]) raw = sorted(raw,key=lambda x:-x[0]) # print(raw) offset = 0 sum = 0 for ra in raw: if offset + ra[1] <= n: sum = sum + ra[1] * ra[0] offset = offset + ra[1] else: sum = sum + (n - offset) * ra[0] offset = n break print(sum) calculate(N, M, ARR, BRR)
总结
这道题体现了审题的重要性,1<=Bi<=N这个条件告诉咱们全部操做的卡面均可以被用上。
在此考察了,把现实问题抽象成排序问题的能力。
而后就是根据目前的复杂度怎么样优化排序的能力。
※ 另外,我会在个人微信我的订阅号上推出一些文章,欢迎关注