题目:

BZOJ4059

分析:

想了半天没什么想法,百度到一个神仙做法……

设原数列为 \(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(分析时间复杂度)的更多相关文章

  1. 【启发式拆分】bzoj4059: [Cerc2012]Non-boring sequences

    这个做法名字是从武爷爷那里看到的…… Description 我们害怕把这道题题面搞得太无聊了,所以我们决定让这题超短.一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子 ...

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

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

  3. 【BZOJ4059】Non-boring sequences

    Solution 记序列为\(a\),计算出与\(a_i\)相等的前一个元素的位置\(pre_i\),以及后一个元素的位置\(nex_i\),显然,对于那些左端点处于\((pre_i,i]\)以及右端 ...

  4. 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 ...

  5. bzoj4059 [Cerc2012]Non-boring sequences

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4059 [题解] 考虑分治.定义过程solve(l,r)为判断全在[l,r]范围内的所有连续子 ...

  6. BZOJ4059[Cerc2012]Non-boring sequences(扫描线/分治)

    这题正解应该是扫描线,就是发现DP的区间在两个维度都为连续段,于是可以直接扫描线.但不幸的是,扫描线常数过大,无法通过本题. 考虑分治.对于分治区间[l,r],可以记录pre和nxt表示其前/后一次出 ...

  7. 【algo&ds】1.时间复杂度和空间复杂度分析

    1.时间复杂度分析O(f(n)) 分析方法 只关注循环执行次数最多的一段代码 加法原则 乘法原则 高优先级原则 常见时间复杂度量级 多项式量级和非多项式量级.其中,非多项式量级只有两个:O(2^n) ...

  8. 算法初级面试题01——认识时间复杂度、对数器、 master公式计算时间复杂度、小和问题和逆序对问题

    虽然以前学过,再次回顾还是有别样的收获~ 认识时间复杂度 常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作. 时间复杂度为一个算法流程中,常数操作数量的指标.常 ...

  9. 维诺图(Voronoi Diagram)分析与实现(转)

    一.问题描述1.Voronoi图的定义又叫泰森多边形或Dirichlet图,它是由一组由连接两邻点直线的垂直平分线组成的连续多边形组成. 2.Voronoi图的特点(1)每个V多边形内有一个生成元: ...

随机推荐

  1. Linux下汇编语言学习笔记63 ---

    这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...

  2. MU Puzzle HDU - 4662

    Suppose there are the symbols M, I, and U which can be combined to produce strings of symbols called ...

  3. git一个本地仓库连接多个远程仓库

    前言:由于公司的GIT是内网服务器,而在家工作访问不了内网服务器,由此想把本地仓库连接一个外网的GIT服务器(码云),方便不在公司时开发. 原文 某些场合,一个git项目需要能同时使用两个甚至多个远程 ...

  4. POJ2632 Crashing Robots 解题报告

    Description In a modernized warehouse, robots are used to fetch the goods. Careful planning is neede ...

  5. HDU——2063 过山车

    过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  6. Swap Nodes in Pairs(链表操作)

    Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2-&g ...

  7. 怎么让Excel显示时间时候能把秒显示出来

    Excel显示时间一般只显示年月日小时分钟怎么能够把秒也显示出来既如下显示 2007-04-11 12:00:00 将单元格格式设为"自定义",在"类型"框中输 ...

  8. GitHub现VMware虚拟机逃逸EXP,利用三月曝光的CVE-2017-4901漏洞

    今年的Pwn2Own大赛后,VMware近期针对其ESXi.Wordstation和Fusion部分产品发布更新,修复在黑客大赛中揭露的一些高危漏洞.事实上在大赛开始之前VMware就紧急修复了一个编 ...

  9. Python学习系列之反射

    反射的定义 根据字符串的形式去某个对象中操作成员 根据字符串的形式去某个对象中寻找成员 根据字符串的形式去某个对象中设置成员 根据字符串的形式去某个对象中删除成员 根据字符串的形式去某个对象中判断成员 ...

  10. vsftpd.conf案例

    1. 匿名服务器的连接(独立的服务器) 在/etc/vsftpd/vsftpd.conf配置文件中添加如下几项:Anonymous_enable=yes (允许匿名登陆)Dirmessage_enab ...