[关闭]
@Junlier 2018-11-05T14:42:36.000000Z 字数 1080 阅读 1749

洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找)

题解
阅读体验:https://zybuluo.com/Junlier/note/1333275

这个题不是很难,但是没有转过来还是难想的
可以先去做一下这个题:洛谷P1901 发射站
蒟蒻发现很多题解都是错的呀,复杂度比较玄学吧
介绍一种标准的的方法

单调栈

我们对于一个人作为方案中右边那个人时我们算答案(为了不算重)
有哪些人我们看不到呢,无非是被它右边的人挡住了是吧
那么从左往右维护一个单调递减的单调栈,单调栈中的人不会出现被挡住的情况(只有看不到的情况后面会讲)
自己想一下这里很简单

二分查找

考虑肯定只有单调栈中的人会被算入答案是吧
并且很容易发现一定是个连续的区间这不废话吗
那么我们在单调栈中二分这个区间的左端点,显然左端点就是左边第一个比高的数
这不就是上面那个发射站的题目了吗
计入答案的就是区间长度啦

代码极其简单。。。

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define rg register
  4. #define ldb double
  5. #define lst long long
  6. #define rgt register int
  7. #define N 500050
  8. using namespace std;
  9. const int Inf=1e9;
  10. il int read()
  11. {
  12. int s=0,m=0;char ch=getchar();
  13. while(!isdigit(ch)){if(ch=='-')m=1;ch=getchar();}
  14. while( isdigit(ch))s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
  15. return m?-s:s;
  16. }
  17. int n,top;lst Ans;
  18. int H[N],stk[N];
  19. il void Calc(rgt x)
  20. {
  21. rgt le=0,ri=top,mid,ret=0;
  22. while(le<=ri)
  23. {
  24. mid=(le+ri)>>1;
  25. if(H[stk[mid]]>x)ret=mid,le=mid+1;
  26. else ri=mid-1;
  27. }
  28. if(!ret)Ans+=top;
  29. else Ans+=top-ret+1;
  30. }
  31. int main()
  32. {
  33. n=read();
  34. for(rgt i=1;i<=n;++i)H[i]=read();
  35. for(rgt i=1;i<=n;++i)
  36. {
  37. Calc(H[i]);
  38. while(top>0&&H[i]>H[stk[top]])--top;
  39. stk[++top]=i;
  40. }return printf("%lld\n",Ans),0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注