【BZOJ4059】Non-boring sequences(分析时间复杂度)
题目:
分析:
想了半天没什么想法,百度到一个神仙做法……
设原数列为 \(a\),对于每一个 \(i\) 求出前一个和后一个和 \(a_i\) 相等的位置 \(pre[i]\) 和 \(nxt[i]\) (如果不存在则分别为 \(-1\) 和 \(n+1\) )。那么如果在一个区间 \([l, r]\) 中存在一个 \(i\) 满足 \(pre[i]<l\) 且 \(nxt[i]>r\) ,说明 \(i\) 在 \([l, r]\) 中只出现了一次,那么任意一个跨越 \(i\) 的 \([l, r]\) 的子区间都是不无聊的,只需要再判断 \([l, i)\) 和 \((i, r]\) 中是否存在这样的 \(i\) 即可。
\(i\) 从两边往中间暴力找(绝对不能从左往右暴力扫一遍!!,那样复杂度就高了),复杂度是 \(O(n\log n)
\)没想到吧!。
下面来证明(感性理解)一下这个神奇的复杂度。正着想比较麻烦,我们倒过来。把递归调用的树画出来(很显然是个二叉树),然后从下往上看,把分治倒过来变成向上合并。每次合并是一个长为 \(l_1\) 的区间和一个长为 \(l_2\) 的区间合起来变成一个长为 \(l_1+l_2+1\) 的区间。而这次合并所花的时间是从两端点暴力找 \(i\) 的时间,即 \(min(l_1, l_2)\) (当然还要乘个 \(2\) 之类,但那不影响复杂度)。这个过程是不是很像启发式合并?于是时间复杂度 \(O(n\log n)\)
代码:
思路清晰,解法自然
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
namespace zyt
{
template<typename T>
inline bool read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != EOF && c != '-' && !isdigit(c));
if (c == EOF)
return false;
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
return true;
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-');
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
inline void write(const char *const s)
{
printf("%s", s);
}
const int N = 2e5 + 10;
int T, n, arr[N], tmp[N], last[N], nxt[N], pre[N];
bool check(const int l, const int r)
{
if (l > r)
return true;
int tmpl = l, tmpr = r;
for (int i = 0; i < (r - l + 1); i++)
if (i & 1)
{
if (pre[tmpl] < l && nxt[tmpr] > r)
return check(l, tmpl - 1) && check(tmpl + 1, r);
++tmpl;
}
else
{
if (pre[tmpr] < l && nxt[tmpr] > r)
return check(l, tmpr - 1) && check(tmpr + 1, r);
--tmpr;
}
return false;
}
int work()
{
read(T);
while (T--)
{
read(n);
for (int i = 0; i < n; i++)
read(arr[i]), tmp[i] = arr[i];
sort(tmp, tmp + n);
int cnt = unique(tmp, tmp + n) - tmp;
for (int i = 0; i < n; i++)
arr[i] = lower_bound(tmp, tmp + cnt, arr[i]) - tmp;
memset(last, -1, sizeof(int[cnt]));
for (int i = 0; i < n; i++)
{
if (~last[arr[i]])
nxt[last[arr[i]]] = i;
pre[i] = last[arr[i]];
last[arr[i]] = i;
}
for (int i = 0; i < cnt; i++)
nxt[last[i]] = n + 1;
if (check(0, n - 1))
write("non-boring\n");
else
write("boring\n");
}
return 0;
}
}
int main()
{
return zyt::work();
}
【BZOJ4059】Non-boring sequences(分析时间复杂度)的更多相关文章
- 【启发式拆分】bzoj4059: [Cerc2012]Non-boring sequences
这个做法名字是从武爷爷那里看到的…… Description 我们害怕把这道题题面搞得太无聊了,所以我们决定让这题超短.一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子 ...
- 【BZOJ-4059】Non-boring sequences 线段树 + 扫描线 (正解暴力)
4059: [Cerc2012]Non-boring sequences Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 440 Solved: 16 ...
- 【BZOJ4059】Non-boring sequences
Solution 记序列为\(a\),计算出与\(a_i\)相等的前一个元素的位置\(pre_i\),以及后一个元素的位置\(nex_i\),显然,对于那些左端点处于\((pre_i,i]\)以及右端 ...
- bzoj4059 [Cerc2012]Non-boring sequences && bzoj5200 [NWERC2017]Factor-Free Tree
https://konnyakuxzy.github.io/BZPRO/JudgeOnline/4059.html https://cn.vjudge.net/problem/Gym-100624D ...
- bzoj4059 [Cerc2012]Non-boring sequences
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4059 [题解] 考虑分治.定义过程solve(l,r)为判断全在[l,r]范围内的所有连续子 ...
- BZOJ4059[Cerc2012]Non-boring sequences(扫描线/分治)
这题正解应该是扫描线,就是发现DP的区间在两个维度都为连续段,于是可以直接扫描线.但不幸的是,扫描线常数过大,无法通过本题. 考虑分治.对于分治区间[l,r],可以记录pre和nxt表示其前/后一次出 ...
- 【algo&ds】1.时间复杂度和空间复杂度分析
1.时间复杂度分析O(f(n)) 分析方法 只关注循环执行次数最多的一段代码 加法原则 乘法原则 高优先级原则 常见时间复杂度量级 多项式量级和非多项式量级.其中,非多项式量级只有两个:O(2^n) ...
- 算法初级面试题01——认识时间复杂度、对数器、 master公式计算时间复杂度、小和问题和逆序对问题
虽然以前学过,再次回顾还是有别样的收获~ 认识时间复杂度 常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作. 时间复杂度为一个算法流程中,常数操作数量的指标.常 ...
- 维诺图(Voronoi Diagram)分析与实现(转)
一.问题描述1.Voronoi图的定义又叫泰森多边形或Dirichlet图,它是由一组由连接两邻点直线的垂直平分线组成的连续多边形组成. 2.Voronoi图的特点(1)每个V多边形内有一个生成元: ...
随机推荐
- bzoj5105 晨跑 数论lcm
“无体育,不清华”.”每天锻炼一小时,健康工作五十年,幸福生活一辈子”在清华,体育运动绝对是同学们生活中 不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不过由于种种原因,每天都早 ...
- MTK TP手势添加
old: #include "tpd.h" #include "tpd_custom_gt9xx.h" #ifndef TPD_NO_GPIO #include ...
- idea导入(import)项目和打开(open)项目的区别
前言: 每次接手老项目,都得从git或svn下载下来,但是如果之前的项目不是用idea写的怎么办,可是你又习惯啦idea,那你必须把项目在idea上跑起来,那是用import还是用open呢,如何抉择 ...
- topshelf生成Windows服务
一. 概述 Visual C# 工程中选取 Windows 服务(Windows Service)选项,可以创建Windows服务程序,这种开发方式对于开发来说不方便调试,今天介绍另外一种生成Win ...
- SQL SERVER 2012 第三章 T-SQL 基本SELECT语句用法,Where子句详细用法
select [all|distinct] [top (<expression>) [Percent] [with ties]] <column list> [from < ...
- hdu - 1394 Minimum Inversion Number(线段树水题)
http://acm.hdu.edu.cn/showproblem.php?pid=1394 很基础的线段树. 先查询在更新,如果后面的数比前面的数小肯定会查询到前面已经更新过的值,这时候返回的sum ...
- Servlet开发(2)
Jsp&Servlet用户登录功能实现(采用MVC模式) 我们使用Jsp&Servlet开发一个用户登录功能的小项目(麻雀大小,但是五脏俱全呦,关键是技术问题!). 数据库:mysql ...
- CLR GC
一.垃圾回收算法 每个应用程序都包含一组根(root),每个根都是一个存储位置,他要么为null,要么指向托管堆的一个对象,类型中定义的静态字段.局部变量.方法参数等都会被认为是根. 垃圾回收器(GC ...
- 正则表达式lookahead and lookbehind zero-length assertions
正则表达式非常好的网站: https://www.regular-expressions.info/lookaround.html ---------------------------------- ...
- Cocos2d-x 脚本语言Lua基本数据结构-表(table)
Cocos2d-x 脚本语言Lua基本数据结构-表(table) table是Lua中唯一的数据结构.其它语言所提供的数据结构,如:arrays.records.lists.queues.sets等. ...