【BZOJ4059】[Cerc2012]Non-boring sequences 分治

【BZOJ4059】[Cerc2012]Non-boring sequences

Description

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

Input

第一行一个正整数T,表示有T组数据。每组数据第一行一个正整数n,表示序列的长度,1 <= n <= 200000。接下来一行n个不超过10^9的非负整数,表示这个序列。

Output

对于每组数据输出一行,输出"non-boring"表示这个序列不无聊,输出"boring"表示这个序列无聊。

Sample Input

4
5
1 2 3 4 5
5
1 1 1 1 1
5
1 2 3 2 1
5
1 1 2 1 1

Sample Output

non-boring
boring
non-boring
boring

题解:首先容易想到线段树做法,由于每个子串都是某个后缀的前缀,所以我们枚举以每个数为结尾的前缀。将这个数的权值设为1,将这个数的前驱的权值设为-1,前驱的前驱设为0,那么如果这个序列是boring的当且仅当该前缀的某个后缀权值和为0。线段树搞一搞就行。

然后又去学了分治做法。首先[l,r]中一定要有一个只出现过一次的数,否则无解。那么所有包含这个数的区间都是不无聊的,我们只需要递归处理左右两边即可。问题是我们怎么找到这个只出现过一次的数。先预处理出前驱和后继,一个数只出现一次等价于前驱<l且后继>r。由于我们的分治不是二分,所以我们每次查找的复杂度应该是余下两个区间长度的较小值。所以我们从两端往中间一个一个找就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=200010;
int flag,n;
struct node
{
	int val,org;
}num[maxn];
int pre[maxn],nxt[maxn];
bool cmp(node a,node b)
{
	return (a.val==b.val)?(a.org<b.org):(a.val<b.val);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void solve(int l,int r)
{
	if(l>r)	return ;
	int mid,i;
	for(i=0;l+i<=r-i;i++)
	{
		if(pre[l+i]<l&&nxt[l+i]>r)
		{
			mid=l+i;
			break;
		}
		if(pre[r-i]<l&&nxt[r-i]>r)
		{
			mid=r-i;
			break;
		}
	}
	if(l+i>r-i)	flag=1;
	if(!flag)	solve(l,mid-1);
	if(!flag)	solve(mid+1,r);
}
void work()
{
	n=rd();
	int i;
	for(i=1;i<=n;i++)	num[i].val=rd(),num[i].org=i,pre[i]=0,nxt[i]=n+1;
	sort(num+1,num+n+1,cmp);
	for(i=1;i<=n;i++)	if(num[i].val==num[i-1].val)	pre[num[i].org]=num[i-1].org,nxt[num[i-1].org]=num[i].org;
	flag=0,solve(1,n);
	if(flag)	printf("boring\n");
	else	printf("non-boring\n");
}
int main()
{
	int T=rd();
	while(T--)	work();
	return 0;
}
时间: 2024-10-03 17:39:41

【BZOJ4059】[Cerc2012]Non-boring sequences 分治的相关文章

bzoj4059 [Cerc2012]Non-boring sequences

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4059 [题解] 考虑分治.定义过程solve(l,r)为判断全在[l,r]范围内的所有连续子序列是不是non-boring的 那么我们预处理每个地方的前一个与它相同的数pre[i]和后一个与它相同的数nxt[i]. 显然对于i属于[l,r],如果存在pre[i]<l,nxt[i]>r,那么任何经过i的连续子序列都合法,所以就分成[l,i-1]和[i+1,r]检测即可. 为了保证复杂度,我

BZOJ 4059 [Cerc2012]Non-boring sequences(启发式分治)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4059 [题目大意] 一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字, 即每个子序列里至少存在一个数字只出现一次. 给定一个整数序列,请你判断它是不是不无聊的. [题解] 预处理每个元素上一次出现位置和下一个出现位置, 我们发现对于一个子序列[L,R]来说, 如果存在pre[i]<L&&nxt[i]>R那么这个子序列一定是满足条件的, 否则就不

BZOJ 4059: [Cerc2012]Non-boring sequences ( )

要快速在一段子序列中判断一个元素是否只出现一次 , 我们可以预处理出每个元素左边和右边最近的相同元素的位置 , 这样就可以 O( 1 ) 判断. 考虑一段序列 [ l , r ] , 假如我们找到了序列中唯一元素的位置 p , 那我们只需检查 [ l , p - 1 ] & [ p + 1 , r ] 是否 non-boring 即可 . 如何检查 序列 [ l , r ] 呢 ? 假如从左往右或者从右往左找 , 最坏情况下是 O( n ) , 总时间复杂度会变成 O( n² ) ; 假如我们从

Boring Class HDU - 5324 (CDQ分治)

Mr. Zstu and Mr. Hdu are taking a boring class , Mr. Zstu comes up with a problem to kill time, Mr. Hdu thinks it’s too easy, he solved it very quickly, what about you guys? Here is the problem: Give you two sequences L1,L2,...,Ln and R1,R2,...,Rn. Y

启发式分治入门 Non-boring sequences UVA - 1608

参考自:https://blog.csdn.net/XY20130630/article/details/50635756 题意:一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,即每个子序列里至少存在一个数字只出现一次.给定一个整数序列,请你判断它是不是不无聊的. 分析:预处理每个元素上一次出现位置和下一个出现位置, 我们发现对于一个子序列[L,R]来说, 如果存在pre[i]<L&&nxt[i]>R那么这个子序列一定是满足条件的, 否则就不满足,那么我

BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线

题目大意:定义一个序列为[不无聊的]当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是[不无聊的] 定义lasti表示第i个元素上一次出现的位置(第一次出现则为0),nexti表示第i个元素下一次出现的位置(最后一次出现则为n+1),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在[lasti+1,i]之间,右端点在[i,nexti?1]之间 我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有

UVA - 1608 Non-boring sequences (分治)

题意:如果一个序列的任意连续子序列中至少有一个只出现一次的元素,则称这个序列式为non-boring.输入一个n(n≤200000)个元素的序列A(各个元素均为109以内的非负整数),判断它是否无聊. 分析: 1.记录下每个元素左边和右边最近的与它值相同的元素的位置. 2.如果某个元素在某一序列中只出现过一次,那这个序列中所有包含该元素的子序列都是non-boring,因此只需要研究在这个序列中以该元素为分界线,其左边和右边的子序列是否无聊即可. 3.因为如果单独从左扫或从右扫,最坏情况可能是在

UVa 1608 (分治 中途相遇) Non-boring sequences

预处理一下每个元素左边和右边最近的相邻元素. 对于一个区间[l, r]和区间内某一个元素,这个元素在这个区间唯一当且仅当左右两边最近的相邻元素不在这个区间内.这样就可以O(1)完成查询. 首先查找整个字符串是否有唯一元素,如果没有则整个序列是无聊的. 有的话,假设这个唯一元素下标是p,那么如果子序列[0, p-1]和[p+1, n-1]是不无聊的,那么这个序列就是不无聊的. 关于查找的话,如果只从一端查找唯一元素,最坏的情况就是O(n).所以可以从两端进行查找,总的时间复杂度是O(nlogn).

HDU 5324 Boring Class【cdq分治】

这就是一个三维排序的问题,一维递减,两维递增,这样的问题用裸的CDQ分治恰好能够解决. 如同HDU 4742(三维排序,一个三维都是递增的) 由于最小字典序比較麻烦,所以要从后面往前面做分治.每一个点的dp值表示以这个点为起点.最长能够延伸多长. 本来是想依照Li排序,可是这样做在cdq的时候实在是太难以处理了.所以就依照idx排序.也就是不须要排序. 然后依照Ri排序,对于左边,保证右边的每一个R值大于左边的值.并用树状数组维护Li(由于Li须要递减.所以树状数组恰好能够维护右边的Li小于左边