运行要求
运行时间限制: 2sec
内存限制: 1024MB
原文链接

题目
现有N张卡片,每张卡片上面写有 整数Ai。现在你对j=1,2,3...M每次进行1次操作。
操作:选择最多Bj枚的卡片(0枚也可以)。把选择的卡片,换成Cj。
求经过M次操作以后,N枚卡片上面写的整数的求和值的最大值。

输入前提条件

  • 输入的全部为整数
  • 1<=N<=10^5
  • 1<=M<=10^5
  • 1<=Ai,Ci<=10^9
  • 1<=Bi<=N

输入
输入都以以下标准从命令行输入

N M
A1 A2 A3 ... An
B1 C1
B2 C2
.
.
.
BM CM

输出

M回操作以后,N枚卡片里整数合值的最大值

例1
输入

3 2
5 1 4
2 3
1 5

输出

14

第1次操作不做操作,第2次操作把1换成5,这样最后的和是5+5+4=14
这个值是最大值

例2
输入

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的纸牌

Atcoder Context ABC 127D.001.jpeg

Atcoder Context ABC 127D.002.jpeg

解题思路
思路1: 刚开始的想法就是先对原始纸牌ARR做一个排序,由小到大。然后在对所有操作做一个排序,面值由大到小,再用面值大的操作去替换面值小的原始纸牌。然后如果想替换原始纸牌ARR里面没有比操作里纸牌的面值要小的话,停止替换。的这个思路是可以的,但是考虑到要对两组10^5的数组分别做排序,时间上是来不及的
Atcoder Context ABC 127D.003.jpeg

思路2: 1<=Bi<=N有这么一个条件,也就是说,所有操作里面的牌的数量都是要小于原始纸牌ARR里面的纸牌的数量的。
操作里的所有的牌,都可以进入原始牌堆ARR
我们要求最大的和,那么操作里面的大牌肯定要进入原始牌堆ARR
那么我们把操作的牌和原始牌堆ARR融合在一起做一个排序就好了,最后取最大的N张牌
但是这个操作要把两组10^5的数组融在一起排序,也就是说,最多要对2*10^5长度的数组排序,时间上也是不允许的。
Atcoder Context ABC 127D.004.jpeg

思路3: 思路2里我们是把操作牌里所有的牌都融合在了原始牌堆ARR里。但是我们排序找最大的那几张牌其实关心的是操作牌的面值而不是操作牌的张数。这里我们把思路2的算法优化一下。原始牌堆ARR里面的每张牌张数为1,操作牌里面的每张牌的张数为相应的值。我们对面值做一个排序,然后一次从上往下取牌,知道取到了N张牌。
我们假设输入是以下

3 2
5 1 4
2 3
3 5

那么操作牌堆里,5有3张,3有2张。按照面值排序,然后再取面值前3位的的牌求和。得到结果是15
Atcoder Context ABC 127D.005.jpeg

代码
这里我只贴上思路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这个条件告诉我们所有操作的卡面都可以被用上。
在此考察了,把现实问题抽象成排序问题的能力。
然后就是根据目前的复杂度怎么样优化排序的能力。

※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
二维码.jpg



伟大不DIAO
1 声望1 粉丝

Done is better than perfect