bzoj4946 [Noi2017]蔬菜(模拟费用流,贪心,线段树)

版权声明:转载附上原文地址即可~欢迎各位神犇来虐~ https://blog.csdn.net/Icefox_zhx/article/details/80862514

首先我们有一个费用流的做法。
因为保质期这个东西不太好限制,我们把每种蔬菜都按照过期时间分成若干类,每类大概x个,这样就相当于我们有了n*p种蔬菜。每种蔬菜在指定时间过期。我们把S的奖励放到每一种蔬菜过期时间最晚的那一类中去。

我们可以建图,S向每一天i连边,容量为m,费用为0,每一天i向所有第i天过期的蔬菜连边,容量为inf,费用为a,每一天i向下一天i+1连边,容量为inf,费用为0(我把这个作用的边连在了蔬菜那边qaq),每种蔬菜向T连边,容量为个数,费用为0,特别的针对每一种蔬菜的最后一类,我们分出1的流量来建费用为s的边。

这样点数是O(np+p),边数是O(np+n+p)的。一天一天的增广费用流,可以跑过前60分。

然后性质1,2直接贪心可以再搞16分。

我们考虑此题正解。

我们发现对于p=i时,我们选择的蔬菜,一定是p=i+1时选择的蔬菜的子集。
自己yy一下为什么…大概就是反证肯定不优。

这样的话我们跑费用流时,每次新增一个点后其实不会有退流的操作!

因此我们可以贪心的来模拟这个费用流的增广过程,并用数据结构加速。

注意到增广到第p天时,此时的流合法就是要求对于任意的i,前i天过期的蔬菜卖出的不能超过min(i,p)*m个。

我们记f[i]表示前i天过期的蔬菜卖出的个数,那么我们就是要求max{f[i]im}<=0

我们用线段树维护这个东西,并用优先队列按价值从大到小维护当前可用蔬菜,每次贪心的取出前m棵蔬菜,看能否选择这种蔬菜(我们贪心的取最晚过期的那棵蔬菜来更新上面的不等式,如果不合法了,就撤销这次操作,并且这种蔬菜以后再不可能被选中)。

复杂度O(nlogn+qm(log n+log q))

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define pi pair<int,int>
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,K;ll ans[N],nn=100000;
struct Icefox{
    int a,s,c,x;
}qq[N];
priority_queue<pi,vector<pi>,less<pi> >q;
struct node{
    int mx,tag;
}tr[N<<2];
inline void pushup(int p){
    tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx);
}
inline void doadd(int p,int val){
    tr[p].mx+=val;tr[p].tag+=val;
}
inline void pushdown(int p){
    if(!tr[p].tag) return;
    doadd(p<<1,tr[p].tag);doadd(p<<1|1,tr[p].tag);tr[p].tag=0;
}
inline void build(int p,int l,int r){
    if(l==r){tr[p].mx=-l*m;return;}
    int mid=l+r>>1;build(p<<1,l,mid);build(p<<1|1,mid+1,r);pushup(p);
}
inline void add(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){doadd(p,val);return;}
    int mid=l+r>>1;pushdown(p);
    if(x<=mid) add(p<<1,l,mid,x,y,val);
    if(y>mid) add(p<<1|1,mid+1,r,x,y,val);pushup(p);
}
inline bool jud(int id){
    int t=qq[id].x?(qq[id].c-1)/qq[id].x+1:nn;
    add(1,1,nn,t,nn,1);if(tr[1].mx<=0) return 1;
    add(1,1,nn,t,nn,-1);return 0;
}
int main(){
//  freopen("vegetables3.in","r",stdin);
//  freopen("a.out","w",stdout);
    n=read();m=read();K=read();
    for(int i=1;i<=n;++i){
        qq[i].a=read();qq[i].s=read();qq[i].c=read();qq[i].x=read();
        q.push(make_pair(qq[i].a+qq[i].s,i));
    }ll res=0;build(1,1,nn);
    for(int i=1;i<=nn;++i){
        int tmp=m;
        while(tmp&&!q.empty()){
            int x=q.top().first,id=q.top().second;q.pop();
            if(!jud(id)) continue;res+=x;--tmp;qq[id].c--;
            if(qq[id].c) q.push(make_pair(qq[id].a,id));
        }ans[i]=res;
    }while(K--) printf("%lld\n",ans[read()]);
    return 0;
}

60+16暴力

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define pi pair<int,int>
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,K;ll ans[N];
struct Icefox{
    int a,s,c,x;
}qq[N];
struct quer{
    int x,id;
    friend bool operator<(quer a,quer b){return a.x<b.x;}
}qu[N];
namespace sol1{
    inline bool cmp(Icefox a,Icefox b){return a.a>b.a;}
    inline void gao(){
        sort(qq+1,qq+n+1,cmp);int now=1;ll res=0;
        for(int i=1;i<=K;++i){
            int tmp=(qu[i].x-qu[i-1].x)*m;
            while(tmp&&now<=n){
                if(qq[now].c>=tmp){qq[now].c-=tmp;res+=(ll)tmp*qq[now].a;if(!qq[now].c) ++now;break;}
                tmp-=qq[now].c;res+=(ll)qq[now].c*qq[now].a;++now;
            }ans[qu[i].id]=res;
        }for(int i=1;i<=K;++i) printf("%lld\n",ans[i]);
    }
}
namespace sol3{
    int h[1002010],num=1,id[1010][1010],tot=0,T,path[1002010];ll dis[1002010];
    bool inq[1002010];
    struct edge{
        int to,next,w,c;
    }data[7000010];
    inline void add(int x,int y,int w,int c){
        data[++num].to=y;data[num].next=h[x];h[x]=num;data[num].w=w;data[num].c=c;
        data[++num].to=x;data[num].next=h[y];h[y]=num;data[num].w=0;data[num].c=-c;
    }inline bool spfa(){
        deque<int>q;memset(dis,-inf,sizeof(dis));memset(path,0,sizeof(path));
        q.push_back(0);dis[0]=0;
        while(!q.empty()){
            int x=q.front();q.pop_front();inq[x]=0;
            for(int i=h[x];i;i=data[i].next){
                int y=data[i].to;if(!data[i].w) continue;
                if(data[i].c+dis[x]>dis[y]){
                    dis[y]=dis[x]+data[i].c;path[y]=i;
                    if(!inq[y]){
                        if(!q.empty()&&dis[q.front()]<dis[y]) q.push_front(y);
                        else q.push_back(y);inq[y]=1;
                    }
                }
            }
        }return path[T];
    }
    inline void gao(){
        T=++tot;
        for(int i=1;i<=n;++i){
            for(int j=1;j<qu[K].x;++j){
                id[i][j]=++tot;if(j!=1) add(id[i][j-1],id[i][j],inf,0);
                if(qq[i].c<=qq[i].x){add(tot,T,qq[i].c-1,0);qq[i].c=0;break;}
                qq[i].c-=qq[i].x;add(id[i][j],T,qq[i].x,0);
            }if(qq[i].c){
                int j=qu[K].x;id[i][j]=++tot;if(j!=1) add(id[i][j-1],id[i][j],inf,0);
                add(tot,T,qq[i].c-1,0);qq[i].c=0;
            }add(tot,T,1,qq[i].s);
        }int now=1;ll res=0;
        for(int i=1;i<=K;++i){
            while(now<=qu[i].x){
                add(0,++tot,m,0);
                for(int j=1;j<=n;++j)
                    if(id[j][now]) add(tot,id[j][now],inf,qq[j].a);++now;
            }while(spfa()){
                int cur=T,low=inf;
                while(path[cur]) low=min(low,data[path[cur]].w),cur=data[path[cur]^1].to;
                res+=(ll)low*dis[T];cur=T;
                while(path[cur]) data[path[cur]].w-=low,data[path[cur]^1].w+=low,cur=data[path[cur]^1].to;
            }ans[qu[i].id]=res;
        }for(int i=1;i<=K;++i) printf("%lld\n",ans[i]);
    }
}
namespace sol2{
    pi a[N<<1];
    inline bool cmp(pi a,pi b){return a.first>b.first;}
    inline void gao(){
        int tot=0;
        for(int i=1;i<=n;++i){
            a[++tot]=make_pair(qq[i].a+qq[i].s,1);
            if(qq[i].c-1) a[++tot]=make_pair(qq[i].a,qq[i].c-1);
        }sort(a+1,a+tot+1,cmp);ll res=0;int now=1;
        for(int i=1;i<=K;++i){
            int tmp=(qu[i].x-qu[i-1].x)*m;
            while(tmp&&now<=tot){
                if(a[now].second>=tmp){a[now].second-=tmp;res+=(ll)tmp*a[now].first;if(!a[now].second) ++now;break;}
                tmp-=a[now].second;res+=(ll)a[now].second*a[now].first;++now;
            }ans[qu[i].id]=res;
        }for(int i=1;i<=K;++i) printf("%lld\n",ans[i]);
    }
}
int main(){
    freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
    n=read();m=read();K=read();bool fl1=1,fl2=1;
    for(int i=1;i<=n;++i){
        qq[i].a=read();qq[i].s=read();qq[i].c=read();qq[i].x=read();
        if(qq[i].x) fl1=0;if(qq[i].s) fl2=0;
    }for(int i=1;i<=K;++i) qu[i].id=i,qu[i].x=read();sort(qu+1,qu+K+1);
    if(fl1&&fl2) sol1::gao();
    else if(fl1) sol2::gao();
    else sol3::gao();
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页