【題解】NOI2017 蔬菜(貪心)

【題解】NOI2017 蔬菜(貪心)

考慮這樣一個事實:

假如你在很長的一段時間內賣了很多蔬菜,但其中只有\(p\)天你賣了菜。那麼其實你在\(p\)天內也可以完成同樣的操作。

這是因爲

  1. 菜的收益不隨時間而改變
  2. 菜不存在體積的區別

題目每天消失固定\(x_i\)蔬菜的限制可以看做每個蔬菜有一個消失時間,每天只能消失\(m\)個蔬菜,那麼我們就先賣消失時間靠後的蔬菜。那麼問題就變得簡單了。現在就是給定一個\(p\),求最大的\(j\le p\)使得\(j\)還有容量,是並查集。

分析一下這裏並查集(路徑壓縮)的複雜度,設查詢次數爲\(q\),複雜度爲\(O(q+1e5*m)\)。(因爲一個點只會被訪問m次)

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;  typedef long long ll;
inline int qr(){
    int ret=0,f=0,c=getchar();
    while(!isdigit(c)) f|=c==45,c=getchar();
    while( isdigit(c)) ret=ret*10+c-48,c=getchar();
    return f?-ret:ret;
}

const int maxn=1e6+5;
int n,m,k;
int a[maxn],s[maxn],c[maxn],x[maxn],r[maxn],sav[maxn],cnt;
ll ans[maxn];
int Find(int x){return x==r[x]?x:r[x]=Find(r[x]);}
priority_queue< pair<int,int> > q;

int main(){
    n=qr(),m=qr(),k=qr();
    for(int t=1;t<=n;++t)
        a[t]=qr(),s[t]=qr(),c[t]=qr(),x[t]=qr(),q.push((pair<int,int>){a[t]+s[t],t});   
    for(int t=1;t<=1e5;++t) r[t]=t,sav[t]=m;
    while(q.size()){
        pair<int,int> now=q.top(); q.pop();
        int tar=0;
        if(x[now.second]) tar=Find(min(100000,(c[now.second]-1)/x[now.second]+1));
        else tar=Find(100000);
        if(!tar) continue;
        --c[now.second]; ans[cnt+1]=ans[cnt]+now.first; ++cnt; --sav[tar];
        if(!sav[tar]) r[Find(tar)]=Find(tar-1);
        if(c[now.second]) q.push((pair<int,int>){a[now.second],now.second});
    }
    while(k--) cout<<ans[min(cnt,m*qr())]<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章