1. 程式人生 > >補題:2018HUD暑期多校訓練第八場-From ICPC to ACM(hdu-6408)(貪心+資料結構)

補題:2018HUD暑期多校訓練第八場-From ICPC to ACM(hdu-6408)(貪心+資料結構)

題目大意:
給你k個月,告訴你每個月原材料的價格,使用者需求量,組裝電腦價格,公司最大產量
以及從本月到下一個月,電腦可存放量,原材料存放價格,電腦存放價格
求k個月下來,公司是否可以滿足使用者需求,如果可以輸出最小成本,否則輸出-1

解題思路:
由題目可知,原材料的儲存量是無限的,那麼我們是否可以貪心的使用原材料價格最小的去組裝電腦(當然這裡需要考慮上存放原材料的錢,使用需要動態更新最小值)。
對於電腦來說,我們可以用一個multiset來維護,先假設公司每個月都最大量生產,存入multiset,然後按照成本從小到大排序,每個月把成本最小的賣掉,進入下個月時,如果存放不了這麼多電腦,則把成本高的丟棄,這樣就可以達到成本最小了。

小編暴力模擬,發現時間要很高,所以需要配合pair來一起維護電腦,第一個存放電腦的成本,第一個存放該成本電腦的數量。
為了後面方便計算以及更新電腦成本小的,我們可以設定一個偏移量sumE,插入時減去這個偏移量,需要用該成本電腦時加上此時的偏移量,類似字首和的效果,則可快速實現該過程。

AC程式碼如下:

#include <bits/stdc++.h>

using namespace std;


long long c[100007],d[100007],m[100007],p[100007];
long long e[150050],R[150050],E[150050];

void init(){
    memset
(e,0,sizeof(e)); memset(R,0,sizeof(R)); memset(E,0,sizeof(E)); } int main() { freopen("l.in","r+",stdin); long long t; scanf("%lld",&t); while(t--){ // init(); long long k; scanf("%lld",&k); for(long long i=1; i<=k; ++i){ scanf
("%lld%lld%lld%lld",&c[i],&d[i],&m[i],&p[i]); } E[0] = e[0] = R[0] = 0; for(long long i=1; i<k; ++i){ scanf("%lld%lld%lld",&e[i],&R[i],&E[i]); } long long _month = 1, flag = 0; long long sumE = 0; long long minRcost = c[1]; long long ans = 0; long long totnum = 0; multiset<pair<int,int>> cpt; while(_month<=k){ minRcost = min(minRcost,c[_month]); if(totnum + p[_month] < d[_month]){ flag=1; break; } totnum += p[_month]; cpt.insert(make_pair(m[_month]-sumE+minRcost,p[_month])); multiset<pair<int ,int>>::iterator pos; totnum -= d[_month]; while(d[_month] && !cpt.empty()){ pos = cpt.begin(); pair<int,int> temp = *pos; int num = temp.second; int mon = temp.first; if(num <= d[_month]){ d[_month]-=num; ans = ans + (mon+sumE)*num; cpt.erase(pos); }else{ num-=d[_month]; ans = ans + (mon+sumE)*d[_month]; cpt.erase(pos); cpt.insert(make_pair(mon,num)); d[_month] = 0; } } while(totnum > e[_month]){ pos = cpt.end(); pos--; pair<int,int> temp = *pos; cpt.erase(pos); if(totnum - temp.second < e[_month]){ temp.second -= (totnum - e[_month]); cpt.insert(make_pair(temp.first, temp.second)); totnum = e[_month]; }else{ totnum -= temp.second; } } if(d[_month]){ flag=1; break; } if(_month<k){ minRcost += R[_month]; sumE += E[_month]; } _month++; } if(flag) printf("-1\n"); else printf("%lld\n",ans); } return 0; }