【BZOJ4946】[NOI2017]蔬菜(贪心)

题面

BZOJ

洛谷

UOJ

题解

忽然发现今年\(NOI\)之前的时候切往年\(NOI\)的题目,就\(2017\)年的根本不知道怎么下手(一定是我太菜了)

这题是一道神仙题(下定义),然而部分分多得不得了,不知道写一个费用流可以得多少分。

我决定先强行插入一下费用流的做法,费用流是这样子的:首先对于蔬菜拆点,每一天拆出一个点,因为蔬菜可以购买的量逐渐递减,因此每一天向下一天连接流量为当前天减少\(d\)的边,费用为\(0\),然后考虑把蔬菜卖出去,那么就是从一个蔬菜拆出来的某一天向汇点连边,因为限制每天购买的总量,所以再对于每一天的购买的蔬菜拆一个点,然后这一天的每一个蔬菜向这个点连容量为\(inf\),费用为蔬菜费用的边,再从这个点向汇点连容量为\(m\),费用为\(0\)的边。显然源点向每个蔬菜的第一天连容量为蔬菜数量,费用为\(0\)的边,至于第一次购买产生的额外贡献,我们把连的那条边拆出一个单位来,再额外链接一下容量为\(1\),费用为第一次购买产生的额外贡献的边。这样子连边就好了(应该是对的)。

跳出来,往正解的方面想。

显然不难发现一个\(O(nQ)\)的贪心,蔬菜会逐渐减少很不好做,我们倒过来,反过来考虑每一天,那么蔬菜的数量变成了每一天都增加每种蔬菜一定量,然后我们需要倒着买蔬菜就好了。可能需要数据结构什么的维护一下,但是大致的复杂度就是上述的东西。

我们现在再正着考虑,假设我们知道我们在\(p\)天的时候的最优解中,买了哪些蔬菜,那么我们可以很容易的得到\(p-1\)天的答案,显然只需要把利润最小的那\(m\)个蔬菜给去掉就好了,因为第\(p-1\)天可以购买的蔬菜不会少于第\(p\)天,在第\(p\)天能够买到的,在\(p-1\)天也一定能够买到。

前面说的不是很清楚,现在考虑如何求解第\(p\)天的答案。我们既然是增加蔬菜,那么这个操作很容易维护,只需要搞一个堆出来,然后每次把当前所拥有的所有蔬菜全部拿出来贪心取就好了,稍微注意一下第一次选产生的额外贡献的细节就好。然后考虑如何递推回去,还是拿一个堆维护,同理注意一下第一次选产生的额外贡献。

既然这么讲了贪心怎么写,是不是觉得其实这就是一个模拟费用流的过程啊,倒推回去就是一个退流的过程,正推的贪心,显然每天只有那么几条路径,用堆维护等价于跑费用流,忽然感觉很妙啊。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define MAX 100100
#define pb push_back
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Node{int v,i;}S[MAX];
bool operator<(Node a,Node b){return a.v<b.v;}
int P=1e5,top,sum;
int n,m,Qry,a[MAX],s[MAX],c[MAX],x[MAX],used[MAX];
ll ans[MAX];
bool vis[MAX];
vector<int> d[MAX];
priority_queue<Node> Q;
int main()
{
n=read();m=read();Qry=read();
for(int i=1;i<=n;++i)a[i]=read(),s[i]=read(),c[i]=read(),x[i]=read();
for(int i=1;i<=n;++i)
if(!x[i])d[P].pb(i);
else d[min(P,(c[i]+x[i]-1)/x[i])].pb(i);
for(int i=P;i;--i)
{
for(int j=0,l=d[i].size();j<l;++j)
Q.push((Node){a[d[i][j]]+s[d[i][j]],d[i][j]});
if(Q.empty())continue;
for(int j=m;j&&!Q.empty();)
{
Node u=Q.top();Q.pop();
if(!vis[u.i])
{
vis[u.i]=true;ans[P]+=u.v;used[u.i]+=1;--j;
if(c[u.i]>1)Q.push((Node){a[u.i],u.i});
}
else
{
int rest=min(j,c[u.i]-used[u.i]-(i-1)*x[u.i]);
ans[P]+=1ll*rest*u.v;used[u.i]+=rest;j-=rest;
if(used[u.i]!=c[u.i])S[++top]=(Node){a[u.i],u.i};
}
}
while(top)Q.push(S[top--]);
}
while(!Q.empty())Q.pop();
for(int i=1;i<=n;++i)sum+=used[i];
for(int i=1;i<=n;++i)
if(used[i]==1)Q.push((Node){-s[i]-a[i],i});
else if(used[i])Q.push((Node){-a[i],i});
for(int i=P-1;i;--i)
{
ans[i]=ans[i+1];
while(sum>i*m&&!Q.empty())
{
Node u=Q.top();Q.pop();u.v*=-1;
if(used[u.i]>1)
{
int rest=min(sum-i*m,used[u.i]-1);
used[u.i]-=rest;sum-=rest;ans[i]-=1ll*rest*u.v;
if(used[u.i]==1)Q.push((Node){-a[u.i]-s[u.i],u.i});
else Q.push((Node){-a[u.i],u.i});
}
else --sum,--used[u.i],ans[i]-=u.v;
}
}
while(Qry--)printf("%lld\n",ans[read()]);
return 0;
}

【BZOJ4946】[NOI2017]蔬菜(贪心)的更多相关文章

  1. bzoj4946: [Noi2017]蔬菜 神烦贪心

    题目链接 bzoj4946: [Noi2017]蔬菜 题解 挺神的贪心 把第次买的蔬菜拆出来,记下每种蔬菜到期的日期,填第一单位蔬菜比其他的要晚 按价格排序后,贪心的往前面可以填的位置填就可以了.找可 ...

  2. BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流

    题目链接: [Noi2017]蔬菜 题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量), ...

  3. [NOI2017]蔬菜 贪心

    题面: [NOI2017]蔬菜 题解: 首先每天蔬菜会变质这点并不好处理,我们考虑让时间倒流,从后向前处理,这样的话就相当于每天都会得到一定量的蔬菜. 这样做有什么好处呢? 我们可以发现一个性质:如果 ...

  4. BZOJ4946 NOI2017蔬菜(贪心+堆)

    容易想到一个费用流做法:将每种蔬菜拆成p种,对应p个过期时间,每一种向可以卖的时间连边,第一次卖的奖励算在最晚过期的一种里.对于天数动态加点.不过这样边数太多了,因为第i天能卖的第i-1天一定能卖,可 ...

  5. bzoj4946 Noi2017 蔬菜

    题目描述 小 N 是蔬菜仓库的管理员,负责设计蔬菜的销售方案. 在蔬菜仓库中,共存放有nn 种蔬菜,小NN 需要根据不同蔬菜的特性,综合考虑各方面因素,设计合理的销售方案,以获得最多的收益. 在计算销 ...

  6. NOI2017蔬菜(贪心)

    小 N 是蔬菜仓库的管理员,负责设计蔬菜的销售方案. 在蔬菜仓库中,共存放有 n 种蔬菜,小 N 需要根据不同蔬菜的特性,综合考虑各 方面因素,设计合理的销售方案,以获得最多的收益. 在计算销售蔬菜的 ...

  7. BZOJ.4946.[NOI2017]蔬菜(贪心 离线)

    题目链接 因为有删除,考虑倒序处理某个p的询问. 那么每天删除xi的蔬菜就变成了每天运来xi的蔬菜.那么我们取当前最优的即可,早取晚取都一样,不需要留给后面取,还能给后面更优的留出空间. 这样就只需考 ...

  8. [NOI2017]蔬菜

    [NOI2017]蔬菜 题目描述 大意就是有\(n\)种物品,第\(i\)个物品有\(c_i\)个,单价是\(a_i\).然后每天你可以卖出最多\(m\)个物品.每天结束后第\(i\)种物品会减少\( ...

  9. 4946: [Noi2017]蔬菜

    4946: [Noi2017]蔬菜 http://www.lydsy.com/JudgeOnline/upload/Noi2017D2.pdf 分析: 贪心. 首先可以将一个蔬菜拆成两个,一个是有加成 ...

随机推荐

  1. 自己写的thinkphp自动生成类

    模型类:CqhModel.class.php <?php namespace Cqh\Model; use Think\Model; class CqhModel extends Model { ...

  2. ArcGIS紧凑型切片读取与应用1-解析(附源码)

    1.前言 ArcGIS 发布的切片服务分为紧凑型切片和传统的分散型切片以及最新ArcGIS por新增的矢量切片.传统的分散型切片面临的问题是文件个数太多,部署拷贝过程十分的耗时,紧凑型切片是对分散型 ...

  3. windows BLE编程 net winform 连接蓝牙4.0

    winform 程序调用Windows.Devices.Bluetoot API 实现windows下BLE蓝牙设备自动连接,收发数据功能.不需要使用win10的UWP开发. 先贴图,回头来完善代码 ...

  4. Python知识梳理

    这是个人学习笔记,非教程,内容会有些混乱 极简教程     数据类型 我们可以使用type()函数类获取对象的类型,Python3中内置数据类型包括:None,int,float,complex,st ...

  5. 【高并发解决方案】7、HAProxy安装和配置

    简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案. HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要 ...

  6. 遇到了ImportError: libmysqlclient_r.so.16: cannot open shared object file: No such file or directory

    解决方法如下: 1. 通过命令查找libmysqlclient_r.so.16 在什么地方,一般是在/usr/lib64/mysql/下面 2. 做一个链接到/usr/lib64 下: ln -s / ...

  7. VXLAN技术在数据中心的应用

    1.VXLAN技术可以通过物理交换机实现,也可以通过服务器实现,这两种实现的后台反应的是CT技术,还是IT技术来主导数据中心虚拟网络的发展. 2.物理交换机实现的VXLAN受限于芯片支持的规则,一般情 ...

  8. Linux 学习笔记之超详细基础linux命令(the end)

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 14---------------- ...

  9. Vue父组件接收不到子组件$emit事件的原因分析

    通常有两种情况: 事件名称不全是小写.事件名称要求全小写. 不是父子关系.这里的父子关系是严格的父子关系,祖孙关系也不行.只能一层一层触发,这在写树形组件时,很容易掉坑里.

  10. 安卓开发之自定义一个view弹出框

    https://www.cnblogs.com/muyuge/p/6152167.html