【NOIP2015模拟11.2】有趣的有趣的家庭菜园

题面



思路一

暴力 \(30\) 分!

很容易打,但是要注意:

  • 开 \(\texttt{long long}\)
  • 是非严格高于(等于是被允许的)

思路二

发现 \(i\) 能收获的条件是只要他为其中一侧的最大值

那么我们设 \(f_i\) 表示 \(1..i\) 中必选 \(i\) 的答案,\(g_i\) 表示 \(i..n\) 中必选 \(i\) 的答案

那么答案就是 \(\max_{i=1}^n{f[i]+g[i]-val[i]}\),其中 \(val[i]\) 表示 \(i\) 草收获果实的贡献。

因为根据 \(f,g\) 的定义可得 \(i\) 处两者都算了,所以就减去重复的贡献

那么考虑怎么求 \(f,g\)

既然两者一个是顺着,一个是倒着,那么我们不妨讨论 \(f\),\(g\) 同理

思考 \(i\) 从 \(j\) 处转移过来,\((i,j)\) 间比 \(i\) 高的草都要除掉

那么 \(f_i = \max(f_j - \sum_{k=j+1}^{i-1} cost_k·[h_k > h_i])(0 \leq j < i)\)

\(cost_k\) 为除掉 \(k\) 所需的费用

它显然是 \(O(n^3)\) 的

我们要考虑优化

思考我们是如何进行转移的?

感性的理解,我们找到 \(j\),把 \(j\) 到 \(i\) 间比 \(i\) 高的草都删除再转移到 \(i\)

那么我们能不能考虑一次性找到最大的 \(f_j - \sum_{k=j+1}^{i-1} cost_k·[h_k > h_i]\)

发现限制条件是 \(h_k > h_i\)

也就是说从左一次往右时 \(h_i\) 会影响比他矮的节点,\(f_j - \sum_{k=j+1}^{i-1} cost_k·[h_k > h_i]\) 就是开区间 \((i..j)\) 中比 \(j\) 高的所有草费用之和

即遇到一个 \(h_i\) 时就算它的影响

于是我们可以用线段树维护,对草的高度先离散化,再对高度建一颗线段树

对于当前点 \(i\),先找线段树 \([1..h_i]\) 中权值最大的点更新 \(f_i\)

然后让线段树中 \([1..h_i-1]\) 的值减去 \(cost_i\)

最后把 \(f_i\) 插入线段树中 \(h_i\) 的位置

终了统计一下答案

正好温习一下线段树的区间加,区间最值,单点修改

记得打懒标记哦!!

\(Code\)

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long LL;
  7. const int N = 1e5 + 5;
  8. int n;
  9. LL seg[N << 2] , tag[N << 2] , f[N] , g[N] , ans;
  10. struct node{
  11. int hign , h , p , c , id;
  12. }a[N];
  13. inline bool cmp(node x , node y){return x.hign < y.hign;}
  14. inline bool cmp1(node x , node y){return x.id < y.id;}
  15. inline void pushup(int k){seg[k] = max(seg[k << 1] , seg[k << 1 | 1]);}
  16. inline void pushdown(int k)
  17. {
  18. if (tag[k] != 0)
  19. {
  20. seg[k << 1] += tag[k];
  21. tag[k << 1] += tag[k];
  22. seg[k << 1 | 1] += tag[k];
  23. tag[k << 1 | 1] += tag[k];
  24. tag[k] = 0;
  25. }
  26. }
  27. inline void update(int x , LL y , int l , int r , int k)
  28. {
  29. if (l == r && l == x)
  30. {
  31. seg[k] = max(seg[k] , y);
  32. return;
  33. }
  34. pushdown(k);
  35. int mid = (l + r) >> 1;
  36. if (x <= mid) update(x , y , l , mid , k << 1);
  37. else update(x , y , mid + 1 , r , k << 1 | 1);
  38. pushup(k);
  39. }
  40. inline void change(int x , int y , LL v , int l , int r , int k)
  41. {
  42. if (x <= l && r <= y)
  43. {
  44. tag[k] += v;
  45. seg[k] += v;
  46. return;
  47. }
  48. pushdown(k);
  49. int mid = (l + r) >> 1;
  50. if (x <= mid) change(x , y , v , l , mid , k << 1);
  51. if (y > mid) change(x , y , v , mid + 1 , r , k << 1 | 1);
  52. pushup(k);
  53. }
  54. inline LL query(int x , int y , int l , int r , int k)
  55. {
  56. if (x <= l && r <= y) return seg[k];
  57. pushdown(k);
  58. LL res = -1e18;
  59. int mid = (l + r) >> 1;
  60. if (x <= mid) res = max(res , query(x , y , l , mid , k << 1));
  61. if (y > mid) res = max(res , query(x , y , mid + 1 , r , k << 1 | 1));
  62. return res;
  63. }
  64. int main()
  65. {
  66. freopen("herbary.in" , "r" , stdin);
  67. freopen("herbary.out" , "w" , stdout);
  68. scanf("%d" , &n);
  69. for(register int i = 1; i <= n; i++) scanf("%d%d%d" , &a[i].hign , &a[i].p , &a[i].c) , a[i].id = i;
  70. sort(a + 1 , a + n + 1 , cmp);
  71. a[1].h = 1;
  72. int s = 1;
  73. for(register int i = 2; i <= n; i++)
  74. {
  75. if (a[i].hign == a[i-1].hign) a[i].h = a[i-1].h;
  76. else a[i].h = ++s;
  77. }
  78. sort(a + 1 , a + n + 1 , cmp1);
  79. memset(seg , 0 , sizeof seg);
  80. memset(tag , 0 , sizeof tag);
  81. for(register int i = 1; i <= n; i++)
  82. {
  83. f[i] = query(1 , a[i].h , 1 , s , 1) + a[i].p;
  84. update(a[i].h , f[i] , 1 , s , 1);
  85. if (a[i].h > 1) change(1 , a[i].h - 1 , -a[i].c , 1 , s , 1);
  86. }
  87. memset(seg , 0 , sizeof seg);
  88. memset(tag , 0 , sizeof tag);
  89. for(register int i = n; i; i--)
  90. {
  91. g[i] = query(1 , a[i].h , 1 , s , 1) + a[i].p;
  92. update(a[i].h , g[i] , 1 , s , 1);
  93. if (a[i].h > 1) change(1 , a[i].h - 1 , -a[i].c , 1 , s , 1);
  94. }
  95. for(register int i = 1; i <= n; i++) ans = max(ans , f[i] + g[i] - a[i].p);
  96. printf("%lld" , ans);
  97. }

JZOJ 4296. 有趣的有趣的家庭菜园的更多相关文章

  1. 【BZOJ4240】有趣的家庭菜园 树状数组+贪心

    [BZOJ4240]有趣的家庭菜园 Description 对家庭菜园有兴趣的JOI君每年在自家的田地中种植一种叫做IOI草的植物.JOI君的田地沿东西方向被划分为N个区域,由西到东标号为1~N.IO ...

  2. bzoj4240: 有趣的家庭菜园(树状数组+贪心思想)

    4240: 有趣的家庭菜园 题目:传送门 题解: 好题!%%% 一开始不知道在想什么鬼,感觉满足二分性?感觉可以维护一个先单调增再单调减的序列? 然后开始一顿瞎搞...一WA 看一波路牌...树状数组 ...

  3. [bzoj4240]有趣的家庭菜园_树状数组

    有趣的家庭菜园 题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4240 数据范围:略. 题解: 第一步比较简单,只需要排序之后,每个数不是在左边就 ...

  4. bzoj4240有趣的家庭菜园(贪心+逆序对)

    对家庭菜园有兴趣的JOI君每年在自家的田地中种植一种叫做IOI草的植物.JOI君的田地沿东西方向被划分为N个区域,由西到东标号为1~N.IOI草一共有N株,每个区域种植着一株.在第i个区域种植的IOI ...

  5. 【bzoj4240】有趣的家庭菜园 贪心+树状数组

    题目描述 对家庭菜园有兴趣的JOI君每年在自家的田地中种植一种叫做IOI草的植物.JOI君的田地沿东西方向被划分为N个区域,由西到东标号为1~N.IOI草一共有N株,每个区域种植着一株.在第i个区域种 ...

  6. JOI2019 有趣的家庭菜园3

    问题描述 家庭菜园专家 JOI 先生在他的家庭菜园中种植了一种叫 Joy 草的植物.在他的菜园里,有 N 个花盆自东向西摆放,编号分别为 \(1, \ldots, N\).每个花盆中有一株 Joy 草 ...

  7. [bzoj4240] 有趣的家庭菜园

    还是膜网上题解QAQ 从低到高考虑,这样就不会影响后挪的草了. 每次把草贪心地挪到代价较小的一边.位置为i的草,花费为min( 1..i-1中更高的草的数目,i+1..n中更高的草的数目 ) 因为更小 ...

  8. 【bzoj4240】 有趣的家庭菜园 树状数组

    这一题最终要构造的序列显然是一个单峰序列 首先有一个结论:一个序列通过交换相邻的元素,进行排序,最少的交换次数为该序列的逆序对个数 (该结论很久之前打表意外发现的,没想到用上了.....) 考虑如何构 ...

  9. [BZOJ4240]有趣的家庭菜园(贪心+树状数组)

    最后数列一定是单峰的,问题就是最小化最后的位置序列的逆序对数. 从大到小加数,每次贪心看放左边和右边哪个产生的逆序对数更少,树状数组即可. 由于大数放哪对小数不产生影响,所以正确性显然. 注意相同数之 ...

  10. BZOJ4240 有趣的家庭菜园(贪心+树状数组)

    显然相当于使序列变成单峰.给原序列每个数按位置标号,则要求重排后的序列原标号的逆序对数最少.考虑将数从大到小放进新序列,那么贪心的考虑放在左边还是右边即可,因为更小的数一定会在其两侧,与它自身放在哪无 ...

随机推荐

  1. React报错之Function components cannot have string refs

    总览 当我们在一个函数组件中使用一个字符串作为ref时,会产生"Function components cannot have string refs"错误.为了解决该错误,使用u ...

  2. VmWare安装Centos后配置Net网络SSH链接问题看这一遍就够了

    1:首先安装VmWare 2:启动时在安装对应的Linux版本,网络就默认 net即可 3:都安装好了之后,注意有一个大坑,输入的账号密码都不能准确登录 最后发现是linux默认的输入法没有启用电脑键 ...

  3. 精华推荐 |【深入浅出Sentinel原理及实战】「原理探索专题」完整剖析Alibaba微服务架构体系之轻量级高可用流量控制组件Sentinel(1)

    Sentinel是什么?不要概念混淆啊! 注意:本Sentinel与Redis服务Sentinel是两回事,压根不是一个概念,请大家不要混肴. Alibaba的Sentinel Sentinel是由阿 ...

  4. Python实验报告(第5章)

    实验5:字符串及正则表达式 一.实验目的和要求 学会使用字符串的常用操作方法和正确应用正则表达式 二.实验环境 软件版本:Python 3.10 64_bit 三.实验过程 1.实例01:使用字符串拼 ...

  5. WireShark抓包入门教学

    wireshark抓包新手使用教程 Wireshark是非常流行的网络封包分析软件,可以截取各种网络数据包,并显示数据包详细信息.常用于开发测试过程各种问题定位.本文主要内容包括: 1.Wiresha ...

  6. [python] 基于NetworkX实现网络图的绘制

    NETWORK CHART(网络图) 代码下载地址 网络图 (或图表或图形)显示了一组实体之间的互连.每个实体由一个或多个节点表示.节点之间的连接通过链接(或边)表示.网络的理论与实现是一个广阔的研究 ...

  7. 主题 2 Shell工具和脚本

    主题 2 Shell工具和脚本 Shell 工具和脚本 · the missing semester of your cs education (missing-semester-cn.github. ...

  8. NET-Core利用etag进行浏览器缓存

    title: .NET Core浏览器缓存方案 date: 2022-12-02 14:17:36 tags: - .NET 缓存介绍及方案 在后端开发中经常会使用缓存来提高接口的响应速度,降低系统的 ...

  9. SQL中常用函数操作

    --在SQL SERVER中批量替换字符串的方法 update [Table] set [Field] = REPLACE([Field],'被替换的原内容','要替换的内容') update HBb ...

  10. 上传图片文件并立即显示到页面使用 javascript实现鼠标拖动画矩形框以及实现固定区域内随意拖动

    首先,你要设计好鼠标事件处理方法,主要是鼠标左键点击,左键释放,还有鼠标移动方法其次,要了解容什么方式,画一个矩形,设计一个方法:DrawRectgle(左上角,右下角),并且要确定当调用这个方法时, ...