Solution

  记序列为\(a\),计算出与\(a_i\)相等的前一个元素的位置\(pre_i\),以及后一个元素的位置\(nex_i\),显然,对于那些左端点处于\((pre_i,i]\)以及右端点处于\([i,nex_i)\)的区间都可以认为是合法的。

  

  那么我们可以将每个区间\([l,r]\)抽象成一个二维平面的点\((l,r)\),每一个元素可以使得一部分区间合法,可以抽象为一个横坐标范围为\([pre_i+1,i]\)且纵坐标范围为\([i,nex_i-1]\)的矩形。对所有矩形进行求交,如果矩形覆盖了所有的合法点(也就是一个上三角形),那么序列就是合法的,否则不合法。

  

​  但是这样跑的非常慢!在BZOJ上AC的扫描线代码在我们OJ上是完全被卡常的.....有没有更加简便的做法?

  

  考虑\(check(l,r)\)表示所有左右端点处于\([l,r]\)的区间是否合法。则答案就是\(check(1,n)\)。

  

​  枚举\(i\in[l,r]\),一旦找到一个\(i\)使得\(pre_i<l\)且\(nex_i>r\),就停下。如果找不到,显然序列\([l,r]\)本身就不合法,直接返回\(false\)。此时我们直接可以得知,左端点处于\([l,i]\)且右端点处于\([i,r]\)的区间全部是合法的!还剩下左右断电都处于\([l,i)\)或\((i,r]\)的区间未检查,返回\(check(l,i-1)\&\&check(i+1,r)\)即可。

  

​  但是枚举这一步的复杂度我们没有保证,最坏总复杂度会达到\(O(n^2)\)。我们需要一个思想:从两头向中间同时推进枚举,直到遇到第一个所需点为止。

  

  时间复杂度是\(T(n)=\max\{T(i)+T(n-i)+\min(n,n-i)\}=O(n\lg n)\)。

  

  为什么呢?感性地讲,如果把递归步骤倒过来看,就是一个启发式合并!关键就在\(min(n,n-i)\)这里,每一层递归贡献的复杂度恰好是关键点与边缘的距离,而我们每次都找最靠近边缘的一个关键点,相当于启发式里面的对较小的部分进行操作的思想一样。

  

  然后就做完了,这种两端向中间枚举的思想很值得学习和思考。

  

  

  

Code

  

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef long long ll;
  6. const int N=200005;
  7. int n,a[N];
  8. int dizlis[N],dizcnt;
  9. int pre[N],nex[N],mark[N];
  10. void Diz(){
  11. dizcnt=n;
  12. memcpy(dizlis,a,(dizcnt+1)*sizeof(int));
  13. sort(dizlis+1,dizlis+1+dizcnt);
  14. dizcnt=unique(dizlis+1,dizlis+1+dizcnt)-dizlis-1;
  15. for(int i=1;i<=n;i++)
  16. a[i]=lower_bound(dizlis+1,dizlis+1+dizcnt,a[i])-dizlis;
  17. }
  18. bool check(int l,int r){
  19. if(l>r) return true;
  20. int p1=l,p2=r;
  21. while(p1<=p2){
  22. if(pre[p1]<l&&nex[p1]>r)
  23. return check(l,p1-1)&&check(p1+1,r);
  24. p1++;
  25. if(pre[p2]<l&&nex[p2]>r)
  26. return check(l,p2-1)&&check(p2+1,r);
  27. p2--;
  28. }
  29. return false;
  30. }
  31. int Main(){
  32. scanf("%d",&n);
  33. for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  34. Diz();
  35. for(int i=1;i<=dizcnt;i++) mark[i]=0;
  36. for(int i=1;i<=n;i++)
  37. pre[i]=mark[a[i]],mark[a[i]]=i;
  38. for(int i=1;i<=dizcnt;i++) mark[i]=n+1;
  39. for(int i=n;i>=1;i--)
  40. nex[i]=mark[a[i]],mark[a[i]]=i;
  41. puts(check(1,n)?"non-boring":"boring");
  42. return 0;
  43. }
  44. int main(){
  45. int T;
  46. scanf("%d",&T);
  47. while(T--) Main();
  48. return 0;
  49. }

【BZOJ4059】Non-boring sequences的更多相关文章

  1. 【bzoj4059】[Cerc2012]Non-boring sequences 分治

    题目描述 我们害怕把这道题题面搞得太无聊了,所以我们决定让这题超短.一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子序列里至少存在一个数字只出现一次.给定一个整数序列, ...

  2. 【题解】CF264B Good Sequences

    [题解]CF264B Good Sequences 具有很明显的无后效性. 考虑\(dp\). 考虑初始条件,显然是\(dp(0)=0\) 考虑转移,显然是\(dp(t)=max(dp[k])+1\) ...

  3. 【LeetCode】Repeated DNA Sequences 解题报告

    [题目] All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: &quo ...

  4. 【BZOJ-4059】Non-boring sequences 线段树 + 扫描线 (正解暴力)

    4059: [Cerc2012]Non-boring sequences Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 440  Solved: 16 ...

  5. 【BZOJ4059】Non-boring sequences(分析时间复杂度)

    题目: BZOJ4059 分析: 想了半天没什么想法,百度到一个神仙做法-- 设原数列为 \(a\),对于每一个 \(i\) 求出前一个和后一个和 \(a_i\) 相等的位置 \(pre[i]\) 和 ...

  6. 【leetcode】Repeated DNA Sequences(middle)★

    All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...

  7. 【Leetcode】【Medium】Repeated DNA Sequences

    All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...

  8. 【HDOJ】4358 Boring counting

    基本思路是将树形结构转线性结构,因为查询的是从任意结点到叶子结点的路径.从而将每个查询转换成区间,表示从该结点到叶子结点的路径.离线做,按照右边界升序排序.利用树状数组区间修改.树状数组表示有K个数据 ...

  9. 【HDOJ】3518 Boring Counting

    后缀数组2倍增可解. #include <cstdio> #include <cstring> #include <cstdlib> #define MAXN 10 ...

随机推荐

  1. 测试目录结构Aegisub【自用笔记】

    手册链接https://aegi.vmoe.info/docs/3.2/Main_Page/ 01,加粗   b标签 1开启 其他或不写则关闭 买{\b1}苹果{\b0}123 02,倾斜   i标签 ...

  2. mac上搭建appium+IOS自动化测试环境(二)

    上一篇: mac上搭建appium+IOS自动化测试环境(一) 9.安装appium-xcuitest-driver依赖 进入WebDriverAgent安装目录,运行bootstrap 首先进入目录 ...

  3. Dede织梦验证码不显示,织梦后台登陆验证码不显示解决方法

    关于"织梦验证码不显示"的解决方法 "织梦验证码无法显示出来"的问题分析? 1.之前显示正常,但是换了服务器后就不能够正常显示:(这种通常是网站程序经过迁移后所 ...

  4. linq与lambda 常用查询语句写法对比

    LINQ的书写格式如下: from 临时变量 in 集合对象或数据库对象 where 条件表达式 [order by条件] select 临时变量中被查询的值 [group by 条件] Lambda ...

  5. rename命令详解

    基础命令学习目录首页 原文链接:http://man.linuxde.net/rename 将main1.c重命名为main.c rename main1.c main.c main1.c renam ...

  6. 使用Python批量修改数据库执行Sql文件

    由于上篇文章中批量修改了文件,有的时候数据库也需要批量修改一下,之前的做法是使用宝塔的phpMyAdmin导出一个已经修改好了的sql文件,然后依次去其他数据库里导入,效率不说极低,也算低了,且都是些 ...

  7. 局域网传输-LED灯搭建局域网:数据传输可达每秒3Gb

    一 : LED灯搭建局域网:数据传输可达每秒3Gb 我们之前介绍了利用可见光通讯技术,通过LED灯光实现精准室内定位的例子.实际上,这种灯泡和技术的用途不止于此,比如,它还能进行无线网络传输. 最近, ...

  8. webpack入门指南-step03

    一.webpack 的使用 webpack简单点来说就就是一个配置文件,所有的魔力都是在这一个文件中发生的. 这个配置文件主要分为三大块 entry 入口文件 让webpack用哪个文件作为项目的入口 ...

  9. Promise.all请求失败重发功能的实现

    写爬虫时遇到用Promise.all同时请求多个页面,不可避免的会遇到某些请求失败的情况,这时可以实现一个"重发失败请求"的功能. Promise.all(task).then() ...

  10. Linux下查看cpu使用率

    top命令 是Linux下常用的性能 分析工具 ,能够实时显示系统 中各个进程的资源占用状况,类似于Windows的任务管理 器.下面详细介绍它的使用方法. top - 02:53:32 up 16 ...