• [bzoj3936][Noi2017]蔬菜【贪心】


    【题目描述】

     http://www.lydsy.com/JudgeOnline/upload/Noi2017D2.pdf

    【题解】

     这道题可以从后往前贪心。

    若我们知道了第i的答案,我们只要去掉(当前个数-前i-1天能取的个数)个价值最小的蔬菜,就能得到第i-1天的答案。

    所以我们现在只要求出最后一天的答案。

    把每种蔬菜拆成两份,前c-1个价值为a,最后一个价值为a+s(按变质的顺序)放入优先队列中,依次取出来放入还能放的地方即可。

    还能放的地方可以用并查集维护。

    复杂度O(n log n)。

    /* --------------
        user Vanisher
        problem bzoj-4946
    ----------------*/
    # include <bits/stdc++.h>
    # define 	ll 		long long
    # define 	N 		1000100
    using namespace std;
    ll read(){
    	ll tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    struct node{
    	ll num,w,d;
    };
    bool operator <(node x, node y){
    	return x.w<y.w;
    }
    priority_queue <node,vector<node> > hp; 
    ll n,m,k,p[N],mp[N],mx,f[N],num[N],cnt,ans[N];
    ll dad(ll x){
    	if (x>100000) return dad(100000);
    	if (f[x]==x) return x;
    	else return f[x]=dad(f[x]);
    }
    int main(){
    	n=read(), m=read(), k=read();
    	for (ll i=1; i<=n; i++){
    		ll a=read(), s=read(), c=read(), x=read(),ti;
    		if (x!=0){
    			ti=(c-1)/x+1;
    			hp.push((node){1,s+a,-ti}); hp.push((node){c-1,a,x});
    		}
    		else {
    			hp.push((node){1,s+a,-100000});
    			hp.push((node){c-1,a,0});
    		}
    	}
    	mx=100000;
    	for (ll i=1; i<=k; i++) p[i]=read(),mx=max(p[i],mx);
    	for (ll i=1; i<=mx; i++) f[i]=i, num[i]=m;
    	while (hp.size()!=0){
    		node now=hp.top();
    		hp.pop();
    		if (now.d<0){
    			ll p=dad(-now.d);
    			if (p==0) continue;
    			num[p]--; mp[++cnt]=now.w;
    			if (num[p]==0) f[p]=dad(f[p-1]);
    			ans[mx]=ans[mx]+now.w;
    		}
    		else {
    			ll p,nownum,newp;
    			if (now.d!=0) p=(now.num-1)/now.d+1,nownum=(now.num-1)%now.d+1;
    				else p=100000, nownum=now.num;
    			newp=dad(p), nownum=nownum+(p-newp)*now.d; p=newp;
    			while (p>0){
    				if (nownum==0&&now.d==0) break;
    				ll del=min(num[p],nownum);
    				for (ll i=1; i<=del; i++) mp[++cnt]=now.w, ans[mx]=ans[mx]+now.w;
    				nownum=nownum-del; num[p]=num[p]-del;
    				if (num[p]==0) f[p]=dad(p-1);
    				newp=dad(f[p-1]);
    				nownum=nownum+(p-newp)*now.d;
    				p=newp;
    			}
    		}
    	}
    	sort(mp+1,mp+cnt+1);
    	ll tot=mx*m,now=ans[mx],l=1;
    	for (ll i=mx-1; i>=1; i--){
    		tot=tot-m;
    		while (cnt-l+1>tot)
    			now=now-mp[l++];
    		ans[i]=now;
    	}
    	for (ll i=1; i<=k; i++)
    		printf("%lld
    ",ans[p[i]]);
    	return 0;
    }


  • 相关阅读:
    Codeforces 379 F. New Year Tree
    「NOI2018」屠龙勇士
    「NOI2018」归程
    深入理解Java枚举类型(enum)
    2018.6.9-学习笔记
    String、StringBuffer与StringBuilder介绍
    HashMap和HashTable到底哪不同?
    HashMap详解
    List,Set和Map详解及其区别和他们分别适用的场景
    Java中高级面试题(1)
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136025.html
Copyright © 2020-2023  润新知