本题有\(O(N)\)的优秀做法,但是因为在考场上不一定能想到,就来分享一种\(O(N\log_2N)\)的做法.虽然有点慢,但是可以过.

前置芝士

  1. 线段树:提高组及以上必备内容,不会的同学可以学习一下.

具体做法

只要会线段树就珂以了,是不是很简单.

先考虑贪心,连续的一定是一次去掉,不可能分成多次去取.



于是答案就是每一行连续的段数之和.

如图,第一行为\(1\)段,第二行\(2\)段,第三行\(2\)段,第四行为\(1\)段,所以答案就是\(1+2+2+1=6\).然后再考虑怎么去算出每一行的段数,如果暴力去求肯定是会T的需要\(O(N^2)\)的时间复杂度,好像也没有什么其他的快速求法,于是再考虑分治,没一次将最下方的若干个完整的一行去掉后就将问题分为若干个子问题,暴力的方法就可以跑过更多的点了,但还是可能被一些特殊的数据卡掉.



如这样一个数据,每一次查找当前区间最低的高度需要\(O(N)\)的时间复杂度,最终的时间复杂度就会退化成\(O(N^2)\).于是可以用线段树优化.时间复杂度就是\(O(N\log_2N)\)(大概).

代码

  1. #include<bits/stdc++.h>
  2. #define rap(i,first,last) for(int i=first;i<=last;++i)
  3. //线段树标准define
  4. #define Lson (now<<1)
  5. #define Rson (now<<1|1)
  6. #define Middle ((left+right)>>1)
  7. #define Left Lson,left,Middle
  8. #define Right Rson,Middle+1,right
  9. #define Now nowleft,nowright
  10. using namespace std;
  11. const int maxN=5e5+7;
  12. const int INF=123123123;//一个极大值
  13. int N;
  14. int tree[maxN*4];
  15. int arr[maxN];
  16. void PushUp(int now)//查询区间最大值
  17. {
  18. tree[now]=min(tree[Lson],tree[Rson]);
  19. }
  20. void Build(int now=1,int left=1,int right=N)//建树
  21. {
  22. if(left==right)
  23. {
  24. tree[now]=arr[left];
  25. return;
  26. }
  27. Build(Left);
  28. Build(Right);
  29. PushUp(now);
  30. }
  31. //不需要修改
  32. int Query(int nowleft,int nowright,int now=1,int left=1,int right=N)//查询区间最小值
  33. {
  34. if(right<nowleft||nowright<left)return INF;
  35. if(nowleft<=left&&right<=nowright)
  36. {
  37. return tree[now];
  38. }
  39. return min(Query(Now,Left),Query(Now,Right));
  40. }
  41. int QueryPlace(int nowleft,int nowright,int m,int now=1,int left=1,int right=N)
  42. //查询区间下一个最小值的位置,m为最小值
  43. {
  44. if(right<nowleft||nowright<left)return INF;
  45. if(left==right)
  46. {
  47. if(tree[now]==m)
  48. return left;
  49. return INF;
  50. }
  51. int result=INF;
  52. if(tree[Lson]<=m)//如果左区间可能存在就先查找左区间
  53. {
  54. result=QueryPlace(Now,m,Left);
  55. }
  56. if(result!=INF)return result;//存在就返回
  57. return QueryPlace(Now,m,Right);//不存在查找右区间
  58. }
  59. long long get(int l,int r/*当前的区间*/,int delhigh/*当前减去的高度*/)
  60. {
  61. if(l>r)return 0;
  62. if(l==r)return arr[l]-delhigh;//l=r时就为当前剩余高度
  63. int minhigh=Query(l,r);
  64. int now=l-1,place;
  65. if(arr[l]==minhigh)now++;//为了防止陷入死循环
  66. long long result=(minhigh-delhigh);//先将最下方可以取的部分直接取掉
  67. while(1)//通过线段树将每一段区间找出并继续加上答案
  68. {
  69. place=QueryPlace(now+1,r,minhigh);
  70. if(place==INF)break;//如果没有下一个位置就退出
  71. result+=get(now+1,place-1,minhigh);//有就加上答案
  72. now=place;
  73. }
  74. if(arr[r]==minhigh)//为了防止陷入死循环
  75. result+=get(now+1,r-1,minhigh);
  76. else
  77. result+=get(now+1,r,minhigh);
  78. return result;//返回答案
  79. }
  80. int main()
  81. {
  82. scanf("%d",&N);//读入
  83. rap(i,1,N)
  84. scanf("%d",&arr[i]);
  85. Build();//建树
  86. printf("%lld\n",get(1,N,0));//输出
  87. return 0;
  88. }

「Luogu P3078 [USACO13MAR]扑克牌型Poker Hands」的更多相关文章

  1. 洛谷 P3078 [USACO13MAR]扑克牌型Poker Hands

    P3078 [USACO13MAR]扑克牌型Poker Hands 题目描述 Bessie and her friends are playing a unique version of poker ...

  2. 洛谷P3078 [USACO13MAR]扑克牌型Poker Hands

    题目描述 Bessie and her friends are playing a unique version of poker involving a deck with \(N\) (\(1 \ ...

  3. P3078 [USACO13MAR]扑克牌型Poker Hands

    题目描述 Bessie and her friends are playing a unique version of poker involving a deck with N (1 <= N ...

  4. 【贪心 思维题】[USACO13MAR]扑克牌型Poker Hands

    看似区间数据结构的一道题 题目描述 Bessie and her friends are playing a unique version of poker involving a deck with ...

  5. 「Luogu P2468 [SDOI2010]粟粟的书架」

    这道题分为两个部分 Part1 前置芝士 前缀和(后缀和,二维前缀和):可以预处理一下数据. 二分查找:可以在较短的时间内找出答案. 具体做法 可以发现\(R,C\)不大,只有\(200\),于是可以 ...

  6. 「Luogu P3820 小D的地下温泉」

    这道题的考点比较多. 前置芝士 BFS(DFS),这两种算法在这道题中并没有什么特别突出的地方,基本就是自己看心情写(本文以DFS为准,所以我心情是好是坏呢?) 连通块,可以将每一个温泉看作一个连通块 ...

  7. 「Luogu P2253 好一个一中腰鼓!」

    就这道题的理论难度来说绿题是有点低了,但是这道题的实际难度来看,顶多黄题,所以建议加强数据或出数据升级版. 前置芝士 线段树:具体可以看我的另一篇文章. 具体做法 暴力的方法想必都会,所以来讲一下正解 ...

  8. 使用ML.NET实现德州扑克牌型分类器

    导读:ML.NET系列文章 本文将基于ML.NET v0.2预览版,重点介绍提取特征的思路和方法,实现德州扑克牌型分类器. 先介绍一下德州扑克的基本牌型,一手完整的牌共有五张扑克,10种牌型分别是: ...

  9. 每个男孩的机械梦「GitHub 热点速览 v.21.41」

    作者:HelloGitHub-小鱼干 机械臂可能在医疗剧中看过,可以用来执行一些精细化的操作,例如:缝合之类的.但这次 Dummy-Robot 让你不仅看看而已,还具备一定的实操性(有一定的动手.经济 ...

随机推荐

  1. Django Web接口开发

    什么是接口 接口一般来讲分为两种: (1)程序内部的接口:方法与方法.模块与模块之间的交互,程序内部抛出的接口,如登录发帖,发帖就必须要登录,如果不登录不能发帖,发帖和登录这两个模块之间就要有交互,就 ...

  2. Django框架之ORM的相关操作(二)

    模型类: class Commongity(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max ...

  3. SQL中AVG、COUNT、SUM、MAX等聚合函数对NULL值的处理

    一.AVG() 求平均值注意AVE()忽略NULL值,而不是将其作为“0”参与计算 二.COUNT() 两种用法 1.COUNT(*) 对表中行数进行计数不管是否有NULL 2.COUNT(字段名) ...

  4. netty(二)---客户端连接

    概述 先了解一下 netty 大概框架图 ,可以看到客户端的创建和服务端最大的区别 - 服务端传入两个 EventLoopGroup,客户端传入一个 EventLoopGroup - channel ...

  5. json 字符串 <----> json 对象

    一,字符串 -->JSON对象 1,转换函数 JSON.parse(json_str): 2,$.parseJSON(json_str):  用的是 jquery 的插件  所以需要引入 jq. ...

  6. 安装多个xcode对homebrew影响

    安装多个xcode,可能会导致无法识别默认使用哪个xcode的情况,这时候执行下列语句,设置默认xcode sudo xcode-select --switch /Applications/Xcode ...

  7. python练习:编写一个函数isIn,接受两个字符串作为参数,如果一个字符串是另一个字符串的一部分,返回True,否则返回False。

    python练习:编写一个函数isIn,接受两个字符串作为参数,如果一个字符串是另一个字符串的一部分,返回True,否则返回False. 重难点:定义函数的方法.使用str类型的find()函数,可以 ...

  8. Centos610安装Jdk1.8

    1.下载JDK 下载:  https://pan.baidu.com/s/15TYsE_wfSb48pS4SpUQKHA 提取码:fsx6 2.上传安装包 上传到linux 并拷贝到/opt/jdk目 ...

  9. Linux - 终端terminal进入交互环境的快捷键

    1. 上一页 ctrl + b 2. 下一页 空格 / ctrl + f 3. 上半页 ctrl + u 4. 下半页 ctrl + d 5. 上一行 k 6. 下一行 j 7. 向上查找 ?key ...

  10. mysql5.7修改root密码

    use mysql; update mysql.user set authentication_string=password('123456') where user='root'; flush p ...