【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. SQL 行列转换数据转换为字符串

    行列转换,将列数据转换为字符串输出 ) SET @center_JZHW = ( SELECT DISTINCT STUFF( ( SELECT ',' + ce_code FROM ap_cente ...

  2. CASE函数

    -> 使用类似switch-case与if-else if -> 语法 •case [字段] •    when 表达式 then 显示数据 •    when 表达式 then 显示数据 ...

  3. Redis管道

    介绍 Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务.客户端请求会遵循以下步骤:客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应并将结果返 ...

  4. java.. C# 使用AES加密互解 采用AES-128-ECB加密模式

    java需要下载外部包, commons codec.jar 1.6  較新的JAVA版本把Base64的方法改成靜態方法,可能會寫成Base64.encodeToString(encrypted, ...

  5. [android] 手机卫士手势滑动切换屏幕

    定义手势识别器 获取手势识别器GestureDetector对象,通过new GestureDetector(context,listener),参数:上下文,监听器 匿名内部类实现简单手势监听器Si ...

  6. 本地计算机上的MySQL服务启动后停止。某些服务在未由其他服务或程序使用时将自动

    重新安装MySQL数据库,由于安装的时候马虎,一路next(事实上,某些地方需要严格的配置,我忘记注意了),导致现在出了很多麻烦. 错误信息: 本地计算机上的MySQL服务启动后停止.某些服务在未由其 ...

  7. webpack4 系列教程(四): 单页面解决方案--代码分割和懒加载

    本节课讲解webpack4打包单页应用过程中的代码分割和代码懒加载.不同于多页面应用的提取公共代码,单页面的代码分割和懒加载不是通过webpack配置来实现的,而是通过webpack的写法和内置函数实 ...

  8. Spring基于XML方式的使用

    一.IoC配置 IoC的配置是通过Spring的xml文件的bean标签进行的. 1.bean标签介绍 bean标签一般是在xml文件进行配置的,xml文件一般样式如下: <?xml versi ...

  9. CSS3背景色透明(兼容IE8)

    标准浏览器通过rgba()实现背景色透明;IE8以下浏览器通过特有滤镜实现背景色透明. 代码如下: 1 /* IE8 */ 2 filter:progid:DXImageTransform.Micro ...

  10. canvas-color的几种设置

    #ffff #642 = #664422 rgb(255,128,0) rgba(100,100,100,0.8) hsl(20,62%,28%) hsla(40,82%,33%,0.6) red