補題:2018HUD暑期多校訓練第八場-From ICPC to ACM(hdu-6408)(貪心+資料結構)
阿新 • • 發佈:2019-01-26
題目大意:
給你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;
}