首页 > 其他 > 详细

[NOI2017]蔬菜(贪心)

时间:2019-01-11 10:55:00      阅读:143      评论:0      收藏:0      [点我收藏+]

神仙题啊!

早上开了两个多小时,终于肝出来了,真香

我们考虑从第 \(10^5\) 天开始递推,先生成 \(p=10^5\) 的解,然后逐步推出 \(p-1,...,2,1\) 的解。

那怎么推出 \(p=10^5\) 的解呢?

现在将题目转化成不停进货然后取 \(m\) 个最大的问题,然后删除最大并 \(push\) 进去。这我们可以想到大根堆。

但是由于政策 增加题目难度,有一个 \(s\)。我们需要先将 \((a_i+s_i,i)\) \(push\) 进去,然后用掉了以后将 \((a_i,i)\) \(push\) 进去。

因为在第 \(i\) 天买了一种蔬菜,当天就无需再用,我们考虑用一个栈存储一下当天用了不是 \(a+s\) 的蔬菜,

然后 \(p=10^5\) 的解生成完了以后,现在就是生成其他解了。

我们每次将最小的 \(sum-i*m\) 个取出然后删除。此时我们也要特判政策。

答案要开 \(long\ long\),时间复杂度 \(O(pm\log n)\)

\(Code\ Below:\)

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define mp make_pair
#define F first
#define S second
using namespace std;
const int maxn=100000+10;
const int lim=100000;
int n,m,k,a[maxn],s[maxn],c[maxn],x[maxn],used[maxn],sum,top;
vector<int> v[maxn];ll ans[maxn];pii sta[maxn];
priority_queue<pii> pq;

inline int read(){
    register int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return (f==1)?x:-x;
}

int main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++){
        a[i]=read(),s[i]=read(),c[i]=read(),x[i]=read();
        if(x[i]==0) v[lim].push_back(i);
        else v[(c[i]+x[i]-1)/x[i]].push_back(i);
    }
    pii u;int rest;
    for(int i=lim;i>=1;i--){
        for(int j=0;j<v[i].size();j++) pq.push(mp(a[v[i][j]]+s[v[i][j]],v[i][j]));
        for(int j=m;j>=1&&!pq.empty();){
            u=pq.top(),pq.pop();
            if(!used[u.S]){
                used[u.S]++;ans[lim]+=u.F;j--;
                if(used[u.S]!=c[u.S]) pq.push(mp(a[u.S],u.S));
            }
            else {
                rest=min(j,c[u.S]-used[u.S]-(i-1)*x[u.S]);
                ans[lim]+=(ll)rest*a[u.S];used[u.S]+=rest;j-=rest;
                if(used[u.S]!=c[u.S]) sta[++top]=mp(a[u.S],u.S);
            }
        }
        while(top) pq.push(sta[top--]);
    }
    while(!pq.empty()) pq.pop();
    for(int i=1;i<=n;i++) sum+=used[i];
    for(int i=1;i<=n;i++){
        if(used[i]==1) pq.push(mp(-a[i]-s[i],i));
        else if(used[i]) pq.push(mp(-a[i],i));
    }
    for(int i=lim-1;i>=1;i--){
        ans[i]=ans[i+1];
        while(sum>i*m&&!pq.empty()){
            u=pq.top(),pq.pop();u.F=-u.F;
            if(used[u.S]==1) ans[i]-=u.F,sum--,used[u.S]=0;
            else {
                rest=min(sum-i*m,used[u.S]-1);
                sum-=rest;used[u.S]-=rest;ans[i]-=(ll)rest*a[u.S];
                if(used[u.S]==1) pq.push(mp(-a[u.S]-s[u.S],u.S));
                else pq.push(mp(-a[u.S],u.S));
            }
        }
    }
    while(k--) printf("%lld\n",ans[read()]);
    return 0;
}

[NOI2017]蔬菜(贪心)

原文:https://www.cnblogs.com/owencodeisking/p/10253806.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!