• 【刷题】BZOJ 4946 [Noi2017]蔬菜


    Description

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

    Solution

    网上大部分都是并查集写法,但是有大神写了非并查集写法,特别容易理解
    首先 (s_i) 的限制,只需将每一个蔬菜分出一个价值为 (a_i+s_i) 且过期时间为该蔬菜最晚的一天的蔬菜
    把时间倒序之后,问题转化为每个蔬菜会在第几天出现,每天贪心选择价值最大的即可
    先求出 (max {p_i }) 的答案,然后递推 ([1,max {pi}-1]) 的答案:每次删除价值最小的 (m) 单位蔬菜,不难发现所有蔬菜的销售时间依然合法

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=100000+10,P=100000;
    int n,m,k,a[MAXN],c[MAXN],x[MAXN],s[MAXN],vis[MAXN];
    ll ans[MAXN],sale[MAXN],tot;
    struct node{
    	ll id,val;
    	inline bool operator < (const node &A) const {
    		return val<A.val;
    	};
    	inline bool operator > (const node &A) const {
    		return val>A.val;
    	};
    };
    std::vector<int> V[MAXN];
    std::queue<node> red;
    std::priority_queue<node> q1;
    std::priority_queue< node,std::vector<node>,std::greater<node> > q2;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    int main()
    {
    	read(n);read(m);read(k);
    	for(register int i=1;i<=n;++i)
    	{
    		read(a[i]),read(s[i]),read(c[i]),read(x[i]);
    		if(x[i]==0)V[P].push_back(i);
    		else V[min(P,(c[i]+x[i]-1)/x[i])].push_back(i);
    	}
    	for(register int i=P;i>=1;--i)
    	{
    		for(register int j=0,lt=V[i].size();j<lt;++j)q1.push({V[i][j],a[V[i][j]]+s[V[i][j]]});
    		ll rest=m;
    		while(!q1.empty()&&rest)
    		{
    			node now=q1.top();
    			q1.pop();
    			if(vis[now.id])
    			{
    				ll res=min(rest,c[now.id]-(i-1)*x[now.id]-sale[now.id]);
    				ans[P]+=1ll*res*a[now.id];sale[now.id]+=res;rest-=res;
    				if(sale[now.id]<c[now.id])red.push(now);
    			}
    			else
    			{
    				vis[now.id]=1;
    				ans[P]+=now.val;sale[now.id]++;rest--;
    				if(sale[now.id]<c[now.id])q1.push((node){now.id,a[now.id]});
    			}
    		}
    		while(!red.empty())q1.push(red.front()),red.pop();
    	}
    	for(register int i=1;i<=n;tot+=sale[i],++i)
    		if(sale[i]==1)q2.push((node){i,a[i]+s[i]});
    		else if(sale[i])q2.push((node){i,a[i]});
    	for(register int i=P-1;i>=1;--i)
    	{
    		ans[i]=ans[i+1];
    		ll rest=tot-1ll*m*i;
    		if(rest<=0)continue;
    		else
    			while(!q2.empty()&&rest)
    			{
    				node now=q2.top();
    				q2.pop();
    				if(sale[now.id]==1)sale[now.id]--,rest--,ans[i]-=now.val;
    				else
    				{
    					int res=min(rest,sale[now.id]-1);
    					sale[now.id]-=res,rest-=res,ans[i]-=1ll*res*now.val;
    					if(sale[now.id]==1)q2.push((node){now.id,a[now.id]+s[now.id]});
    					else if(sale[now.id])q2.push((node){now.id,a[now.id]});
    				}
    			}
    		tot=1ll*m*i;
    	}
    	for(register int i=1,x;i<=k;++i)read(x),write(ans[x],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    怎么导出SQL所有用户表的字段信息
    全面掌握C#中的拖放操作
    C#中使用Hook(钩子)
    如何在winform程序中显示网页
    设置socket.Receive()的等待时延
    局域网QQ(C#版)
    C#实现系统热键的功能
    使用C#在应用程序间发送消息
    某某人整理的c#.net函数列表
    C#串口通信编程类(修改版)
  • 原文地址:https://www.cnblogs.com/hongyj/p/9518013.html
Copyright © 2020-2023  润新知