题面: [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. Awesome Django

     Awesome Django    If you find Awesome Django useful, please consider donating to help maintain it. ...

  2. 学会了vim中的自动补全功能

    好开心,再也不用再多个工具之间切换了,哈哈 擦,功能太弱

  3. 负数取余/整除,Python和C语言的不同

    总结一句:Python中负数整除,是向负无穷取整,所以导致负数取余不对 在数学公式中,两种语言的表示算法都是一样的,都是: r=a-n*[a/n] 以上,r是余数,a是被除数,n是除数. 唯一不同点, ...

  4. TW实习日记:第27天

    今天依旧是磨洋工的一天,说真的,被存在各种问题的后端接口把耐心和动力都给磨没了.于是一天就又在沟通接口问题中度过了,完善了一个新功能,将一个新功能开发到了一半.效率可真是够低的,唉.然后不知道为什么突 ...

  5. JAVA基础学习之路(七)对象数组的定义及使用

    两种定义方式: 1.动态初始化: 定义并开辟数组:类名称 对象数组名[] = new 类名称[长度] 分布按成:类名称 对象数组名[] = null: 对象数组名 = new 类名称[长度]:   2 ...

  6. Pandas基础教程

    pandas教程 更多地可以 参考教程 安装 pip install pandas pandas的类excel操作,超级方便: import pandas as pd dates = pd.date_ ...

  7. Java进阶知识点:不要只会写synchronized - JDK十大并发编程组件总结

    一.背景 提到Java中的并发编程,首先想到的便是使用synchronized代码块,保证代码块在并发环境下有序执行,从而避免冲突.如果涉及多线程间通信,可以再在synchronized代码块中使用w ...

  8. sql server存储特殊字符解决办法

    好久没来院子了,最近在学java了,再加上项目比较紧,最近都没怎么上,其实这几天在项目中学到不少东西,都能写下来,但是久而久之就忘了,还是得养成及时总结的好习惯啊,还有有时间一定要把那个小项目整理下来 ...

  9. ubuntu16.04图形界面安装中文输入法,中文展示

    打开system Settings 设置   打开设置语言   安装Language Support   点击installed languages 选择chinese 打勾,安装   安装IBus框 ...

  10. 聊聊、dubbo 找不到 dubbo.xsd 报错

    平常在用 Dubbo 的时候,创建 xml 会提示 http://code.alibabatech.com/schema/dubbo/dubbo.xsd 找不到. 大家可以去 https://gith ...