题面: [NOI2017]蔬菜

题解:

  首先每天蔬菜会变质这点并不好处理,我们考虑让时间倒流,从后向前处理,这样的话就相当于每天都会得到一定量的蔬菜。

  这样做有什么好处呢?

  我们可以发现一个性质:如果从后向前贪心卖菜,那么因为现在可以卖的菜,以后一定还可以卖(因为变成了得到菜),因此贪心就是对的了。

  因此我们用堆维护一下,从后向前贪心的卖菜,每次优先卖价格高的,第一次卖的菜价格要加上奖励的贡献,并且只能先卖一个,因为卖完这一个之后的同种菜没有奖励了,相当于贡献有变化。

  这样向前一直贪到第一天,于是我们就得到了卖1 ~ 100000天的最高收入。

  那么已知1到100000的最高收入,如何利用之前的决策信息快速的得知1到99999的最高收入呢?

  我们发现,这2者之间唯一的差别就是少买了最多m个蔬菜。

  那么我们已知我们已经卖了have个蔬菜,已知1到now这么多天最多卖$m * now$个蔬菜,那么如果$have > m * now$,我们就要舍弃部分蔬菜使得$have <= m * now$成立。

  用堆维护,每次撤销卖价最低的蔬菜即可,注意如果撤销的这个蔬菜是剩下的最后一个了,那么代价要加上奖励的代价。

  为什么这样是对的呢?

  因为如果这个菜是在后面被卖出的话,前面肯定也可以卖,所以如果我们撤销了某天卖出的蔬菜,可以看做在这天后面卖出的蔬菜被挤上来顶替了这个被撤销的蔬菜,于是代价就会始终等价于撤销了最后一天卖出的蔬菜。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define R register int
  4. #define AC 100100
  5. #define LL long long
  6.  
  7. int n, m, k, can;//存下浪费了多少的卖菜名额
  8. const int maxn = ;
  9. LL ans[AC], last[AC], sum[AC], d[AC], have[AC], v[AC], s[AC], c[AC];
  10. int sta[AC], top;
  11. //每一天的答案,每种菜最后一天出现是在哪一天,那天有多少这种菜,d表示以后每天增加多少
  12. //have表示这种菜现在卖出了多少,a表示卖菜的基础收益,s表示额外收益,c表示初始库存
  13. int Head[AC], Next[AC], date[AC], tot;
  14. struct node{
  15. LL v;
  16. int id;
  17. };
  18.  
  19. struct cmp2{//小根堆
  20. bool operator () (node a, node b){ return a.v > b.v;}
  21. };
  22.  
  23. struct cmp{//大根堆
  24. bool operator () (node a, node b){return a.v < b.v;}
  25. };
  26.  
  27. priority_queue<node, vector<node>, cmp> q;
  28. priority_queue<node, vector<node>, cmp2> q2;
  29.  
  30. inline int read(){
  31. int x = ;char c = getchar();
  32. while(c > '' || c < '') c = getchar();
  33. while(c >= '' && c <= '') x = x * + c - '', c = getchar();
  34. return x;
  35. }
  36.  
  37. inline void add(int f, int w){
  38. date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot;
  39. }
  40.  
  41. void pre()
  42. {
  43. n = read(), m = read(), k = read();
  44. for(R i = ; i <= n; i ++)
  45. {
  46. v[i] = read(), s[i] = read(), c[i] = read(), d[i] = read();
  47. if(d[i])
  48. {
  49. last[i] = c[i] / d[i] + , sum[i] = c[i] - (c[i] / d[i]) * d[i];
  50. if(!sum[i]) sum[i] = d[i], last[i] --;
  51. add(last[i], i);//把这个菜挂在第一次出现的地方
  52. }
  53. else last[i] = maxn, sum[i] = c[i], add(maxn, i);
  54. }
  55. }
  56.  
  57. void get()//从后向前贪心,小根堆维护撤销
  58. {
  59. for(R i = ; i <= n; i ++)//把卖出去的菜压入栈中
  60. if(have[i] == ) q2.push((node){v[i] + s[i], i});
  61. else if(have[i]) q2.push((node){v[i], i});
  62. for(R i = maxn - ; i; i --)//向前撤销
  63. {
  64. ans[i] = ans[i + ];//初始状态
  65. LL y = m;
  66. if(i * m >= can) continue;
  67. else y = can - i * m, can -= y;
  68. while(y && !q2.empty())
  69. {
  70. node x = q2.top();
  71. if(have[x.id] == ) ans[i] -= x.v, q2.pop(), -- y;//如果只剩一个了就要弹出去了
  72. else
  73. {
  74. if(have[x.id] > y)//如果反正取不完的话就随便取,否则就要注意不能取完了
  75. {
  76. have[x.id] -= y, ans[i] -= x.v * y, y = ;
  77. if(have[x.id] == )
  78. q2.pop(), x.v += s[x.id], q2.push(x);
  79. }
  80. else
  81. {
  82. ans[i] -= x.v * (have[x.id] - ), y -= (have[x.id] - );
  83. have[x.id] = , q2.pop(), x.v += s[x.id], q2.push(x);
  84. }
  85. }
  86. }
  87. }
  88. }
  89.  
  90. void build()//从后向前贪心,大根堆维护取值
  91. {
  92. for(R i = maxn; i; i --)
  93. {
  94. for(R j = Head[i]; j; j = Next[j])
  95. {
  96. int x = date[j];
  97. q.push((node){v[x] + s[x], x});
  98. }
  99. while(top) q.push((node){v[sta[top]], sta[top]}), -- top;//放回去
  100. LL y = m;
  101. while(y && !q.empty())
  102. {
  103. node x = q.top();
  104. if(!have[x.id])
  105. {
  106. q.pop(), ans[maxn] += x.v, x.v -= s[x.id];
  107. have[x.id] = , -- y, q.push(x);
  108. }
  109. else
  110. {
  111. LL tmp = (last[x.id] - i) * d[x.id] + sum[x.id] - have[x.id];//获取这个菜还剩多少
  112. if(tmp >= y) have[x.id] += y, ans[maxn] += x.v * y, y = ;//还有就不用pop了
  113. else
  114. {
  115. y -= tmp, have[x.id] += tmp, q.pop();
  116. ans[maxn] += x.v * tmp;
  117. if(d[x.id]) sta[++top] = x.id;
  118. }
  119. }
  120. }
  121. can += m - y;
  122. }
  123. }
  124.  
  125. void work()
  126. {
  127. for(R i = ; i <= k; i ++)
  128. printf("%lld\n", ans[read()]);
  129. }
  130.  
  131. int main()
  132. {
  133. // freopen("in.in", "r", stdin);
  134. pre();
  135. build();//先获取最后一个的值
  136. get();//再倒退出整个数组
  137. work();
  138. // fclose(stdin);
  139. return ;
  140. }

[NOI2017]蔬菜 贪心的更多相关文章

  1. NOI2017蔬菜(贪心)

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

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

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

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

    [BZOJ4946][NOI2017]蔬菜(贪心) 题面 BZOJ 洛谷 UOJ 题解 忽然发现今年\(NOI\)之前的时候切往年\(NOI\)的题目,就\(2017\)年的根本不知道怎么下手(一定是 ...

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

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

  5. [NOI2017]蔬菜

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

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

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

  7. 4946: [Noi2017]蔬菜

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

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

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

  9. uoj318 [NOI2017]蔬菜 【贪心 + 堆 + 并查集】

    题目链接 uoj 题解 以前看别人博客,在考场上用费用流做,一直以为这题是毒瘤网络流题 没想到竟然是贪心模拟题... 如果只有一个蔬菜呢?这就是一个经典的普及难度的贪心,正着推面临优先选择的困难,而逆 ...

随机推荐

  1. SIFT 特征点提取算法

    SIFT特征点相对于ORB计算速度较慢,在没有GPU加速情况下,无法满足视觉里程计的实时性要求,或者无法运行在手机平台上,但是效果更好,精度更高.在应用时可以择优选取,了解其本质原理的动机是为了自己使 ...

  2. ubuntu14.04上安装Java

    apt-get安装 sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get install orac ...

  3. E2E test protractor selenium

    E2E Test和传统的Unit Test不同的是:(1)不涉及代码层面,不会去测试某段代码是否正确或者某行代码是否被覆盖(2)它是从用户的角度出发,用来测试一个应用的流程是否符合预期. 一 Sele ...

  4. centos 6.5 启动时卡在进度条位置无法进入系统解决办法。

    今天公司服务器因突然断电导致phddns 花生壳 启动失败,一直卡在启动进度条页面. 解决办法 1.按F5查看卡在什么位置, 2.查看解决方法:程序卡住的情况下,直接备份资料后,卸载程序重启就可以了. ...

  5. Jedis 与 MySQL的连接线程安全问题

    Jedis的连接是非线程安全的 下面是set命令的执行过程,简单分为两个过程,客户端向服务端发送数据,服务端向客户端返回数据,从下面的代码来看:从建立连接到执行命令是没有进行任何并发同步的控制 pub ...

  6. 【未完】训练赛20190304:KMP+树状数组+线段树+优先队列

    头炸了啊,只做出L题,前两天刚看的Shawn zhou的博客学习的,幸亏看了啊,否则就爆零了,发现题目都是经典题,线段树,KMP,我都没看过,最近又在复习考研,真后悔大一大二没好好学习啊,得抽时间好好 ...

  7. 计蒜客蓝桥杯模拟赛 后缀字符串:STL_map+贪心

    问题描述 一天蒜头君得到 n 个字符串 si​,每个字符串的长度都不超过 10. 蒜头君在想,在这 n 个字符串中,以 si​ 为后缀的字符串有多少个呢? 输入格式 第一行输入一个整数 n. 接下来  ...

  8. linux服务器操作小技巧

    python程序后台一直运行,并将打印信息输出到文件中 nohup -u test.py > out.txt & -u 表示无缓冲,直接将打印信息输出带文件中 &表示程序后台运行

  9. HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)

    Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...

  10. Check the string

    A has a string consisting of some number of lowercase English letters 'a'. He gives it to his friend ...