運行要求
運行時間限制: 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這個條件告訴咱們全部操做的卡面均可以被用上。
在此考察了,把現實問題抽象成排序問題的能力。
而後就是根據目前的複雜度怎麼樣優化排序的能力。
※ 另外,我會在個人微信我的訂閱號上推出一些文章,歡迎關注