zoukankan      html  css  js  c++  java
  • BZOJ.4946.[NOI2017]蔬菜(贪心 离线)

    题目链接

    因为有删除,考虑倒序处理某个p的询问。
    那么每天删除xi的蔬菜就变成了每天运来xi的蔬菜。那么我们取当前最优的即可,早取晚取都一样,不需要留给后面取,还能给后面更优的留出空间。
    这样就只需考虑现在了。于是我们能得到p为某个值的答案。多次询问显然需要递推。
    而p-1与p相比只是少卖了m的蔬菜。把收益最小的m个删掉即可。

    注意堆的插入删除顺序。
    复杂度(O(mqlogn))

    还有一种求询问p的方法,是直接按蔬菜价值排序,然后每次找到其出现位置往前覆盖。如果某天已卖m则用并查集合并掉。
    递推的时候sort一遍挨着删就可以。


    感觉离散化后线段树可做,第一次购买收益单独算一个,每个节点维护区间当前蔬菜种数、蔬菜总量、每天减少量。
    正序做,每一天就选m个最大的,然后减掉这m个。
    在某种蔬菜消失的那天直接Delete掉这种蔬菜(如果剩下1个下一天则Delete掉拆开的第一次购买收益)。
    这样复杂度还与m无关。
    不过...算了我就想想...写了写就弃了。


    //9424kb	1132ms
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 400000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    #define mp std::make_pair
    #define pr std::pair<LL,int>
    #define MAX 100000
    typedef long long LL;
    const int N=1e5+3;
    
    int A[N],S[N],tot[N],dec[N],use[N];
    LL Ans[N];
    std::vector<int> v[N];
    std::queue<int> tmp;
    std::priority_queue<pr> q1;
    std::priority_queue<pr,std::vector<pr>,std::greater<pr> > q2;
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    
    int main()
    {
    	int n=read(),m=read(),Q=read();
    	for(int i=1; i<=n; ++i)
    	{
    		A[i]=read(),S[i]=read(),tot[i]=read(),dec[i]=read();
    		if(!dec[i]) v[MAX].push_back(i);//上界!
    		else v[std::min(MAX,(tot[i]+dec[i]-1)/dec[i])].push_back(i);
    	}
    	LL ans=0;
    	for(int i=MAX; i; --i)
    	{
    		for(int j=0,k,l=v[i].size(); j<l; ++j)//处理第一次购买 
    			k=v[i][j], q1.push(mp(A[k]+S[k],k));
    		for(int l=m; l&&!q1.empty(); q1.pop())
    		{
    			int x=q1.top().second;
    			if(!use[x])
    				use[x]=1, ans+=q1.top().first, q1.push(mp(A[x],x)), --l;
    			else
    			{
    				int cnt=std::min(l,tot[x]-use[x]-(i-1)*dec[x]);
    				ans+=1ll*q1.top().first*cnt, l-=cnt;
    				if((use[x]+=cnt)!=tot[x]/*x=0可能会用完!*/) tmp.push(x);//delete
    			}
    		}
    		while(!tmp.empty()) q1.push(mp(A[tmp.front()],tmp.front())), tmp.pop();
    	}
    	Ans[MAX]=ans; int sum=0;
    	for(int i=1; i<=n; sum+=use[i++])
    		if(use[i]==1) q2.push(mp(A[i]+S[i],i));
    		else if(use[i]) q2.push(mp(A[i],i));
    	for(int i=MAX-1; i; --i)
    	{
    		Ans[i]=ans=Ans[i+1];
    		if(sum<=m*i) continue;//总数不够!
    		for(int l=sum-i*m/*同上!*/; l&&!q2.empty(); )
    		{
    			int x=q2.top().second;
    			if(use[x]==1) ans-=q2.top().first, --l, q2.pop();
    			else
    			{
    				int cnt=std::min(l,use[x]-1);
    				ans-=1ll*q2.top().first*cnt, l-=cnt;
    				if((use[x]-=cnt)==1) q2.pop(), q2.push(mp(A[x]+S[x],x));
    			}
    		}
    		sum=i*m, Ans[i]=ans;
    	}
    	while(Q--) printf("%lld
    ",Ans[read()]);
    
    	return 0;
    }
    
  • 相关阅读:
    从新注册 .DLL CMD 运行regsvr32 *.dll注册该DLL 或 regsvr32 /s *.DLL 求证
    短信猫 TIdTCPServer TIdTCPClient
    转:Delphi和Office程序开发 --不错可查阅
    主窗体里面打开子窗体&&打印饼图《Delphi 6数据库开发典型实例》--图表的绘制
    TeeChart Pro 5.0
    软件打开时间、窗体透明度、背景色---《用delphi开发共享软件》-15.1任务管理器
    设置随机启动--《用delphi开发共享软件》-15.1任务管理器
    实现窗体随着鼠标移动(控件)--《用delphi开发共享软件》-15.1任务管理器
    第二百六十一节,Tornado框架模板引擎本质
    第二百六十节,Tornado框架-内置模板方法
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9669394.html
Copyright © 2011-2022 走看看