●UVA 1608 Non-boring sequences

题链:

https://vjudge.net/problem/UVA-1608#author=chenchonghan
题解:

分治
如果一个区间[l,r]里面在p位置出现了一个只出现一次的元素,(如果不存在该元素,该区间就是boring的)
那么必然包含p的子区间都是non-boring的。
即如果存在boring的区间,必然是[l,p-1],[p+1,r]的子区间。
所以继续递归处理上面两个区间即可。
(判断某个元素是否在区间里只出现一次,只需考虑它左边第一个与它相同的元素或它右边第一个相同的元素是否在该区间里)
(需要O(N)预处理L[i],R[i]分别表示该位置左边和右边第一个与该位置相同的位置)
复杂度最坏O(N^2),不够高效。
优化就是从区间的两端同时寻找是否存在该区间内只出现一次的元素。

代码:

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;
int N;
int L[MAXN],R[MAXN];
void read_and_prework(){
	static int A[MAXN],tmp[MAXN],tnt;
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
		scanf("%d",&A[i]),tmp[i]=A[i];
	sort(tmp+1,tmp+N+1);
	tnt=unique(tmp+1,tmp+N+1)-tmp-1;
	for(int i=1;i<=N;i++)
		A[i]=lower_bound(tmp+1,tmp+tnt+1,A[i])-tmp;
	fill(tmp+1,tmp+tnt+1,0);
	for(int i=1;i<=N;i++)
		L[i]=tmp[A[i]],tmp[A[i]]=i;
	fill(tmp+1,tmp+tnt+1,N+1);
	for(int i=N;i>=1;i--)
		R[i]=tmp[A[i]],tmp[A[i]]=i;
}
bool divide(int l,int r){
	if(l==r) return 1;
	bool fg=1;
	int i=l,j=r,k=0;
	while(i<=j){
		if(L[i]<l&&R[i]>r){k=i; break;}
		else i++;
		if(L[j]<l&&R[j]>r){k=j; break;}
		else j--;
	}
	if(!k) return 0;
	if(l<=k-1) fg&=divide(l,k-1);
	if(k+1<=r) fg&=divide(k+1,r);
	return fg;
}
int main(){
	int Case; scanf("%d",&Case);
	while(Case--){
		read_and_prework();
		if(divide(1,N)) printf("non-boring");
		else printf("boring");
		printf("\n");
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/zj75211/p/8541827.html

时间: 2024-08-30 01:24:45

●UVA 1608 Non-boring sequences的相关文章

UVa 1608,Non-boring sequences

好诡异的一个题啊 紫书上关于从左边找还是从两边往中间找的讨论没有看懂,怎么一下就找到唯一的元素了(⊙_⊙?) 方法就是用的书上讲的方法,类似于uva 11572,不过这个题需要预处理存下两边的最近的相同数的位置 for (int i=1;i<=n;i++) { prev[i]=r[a[i]]; next[prev[i]]=i; r[a[i]]=i;}//记录元素a[i]上次出现的位置,因为是从左向右遍历,所以上次出现的位置正好是prev[i]要求的 //prev[i],与 i位置的元素 相同的左

uva 1608 不无聊的序列(附带常用算法设计和优化策略总结)

uva 1608 不无聊的序列(附带常用算法设计和优化策略总结) 紫书上有这样一道题: 如果一个序列的任意连续子序列中都至少有一个只出现一次的元素,则称这个序列时不无聊的.输入一个n个元素的序列,判断它是不是无聊的序列.n<=200000. 首先,在整个序列中找到只出现一次的元素ai.如果不能找到,那它就是无聊的.不然,就可以退出当前循环,递归判断[1, i-1]和[i+1, n]是不是无聊的序列.然而怎么找ai很重要.如果从一头开始找,那么最差情况下的时间复杂度就是O(n^2)的.而如果从两头

UVA 1608 Non-boring sequences

#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=200100; const int INF=1<<29; int n,a[maxn]; int L[maxn],R[maxn]; map<int,int&

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

UVA 1608 Non-boring sequences (分冶+递归)

一.题目概述 二.题目释义 要求序列s的所有子序列,若所有这些子序列中均存在一个自己序列内是唯一的数,则称这个序列s是不无聊的 三.思路分析 从序列s开始考虑,序列s的整个长度为n,若序列s中存在一个唯一数,则所有包含了这个数的子序列都是不无聊的,那么有可能不满足的要求的子序列只会存在于这个唯一数的左区间与有区间,那么问题就被分冶为了看左区间与右区间内是否有一个唯一数,若找到了,则继续这样递归下去,直到靠近区间长度为1为止 那么我们怎么样做到快速的查找在区间[l,r]内存在着唯一数呢,我们容易想

UVA - 1608 Non-boring sequences(分治法)

题目: 如果一个序列的任意连续的子序列中至少有一个只出现一次的元素,则称这个序列是不无聊的.输入一个n(n≤200000)个元素的序列A(各个元素均为109以内的非负整数),判断它是不是不无聊的. 思路: 分治法,平常确实用的非常的少,这次借这个题目熟悉一下.代码思路是学习的紫书上的代码的. 在[L,R]范围内枚举是唯一的数,从这个数的左右两边开始判断是不是左右两边的序列都符合唯一性条件.(包含这个唯一数的区间都是符合条件的,所以只要在从两边开始枚举就可以了.) 代码: #include <bi

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

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

UVA 1608 Non-boring sequence 不无聊的序列(分治,中途相遇)

题意:给你一个长度为n序列,如果这个任意连续子序列的中都有至少出现一次的元素,那么就称这个序列是不无聊的,判断这个序列是不是无聊的. 先预处理出每个元素之前和之后相同元素出现的位置,就可以在O(1)的时间判断出一个元素在一个区间内是否唯一. 每次从大的序列中找一个唯一元素,包含这个元素的就不用判断了,那么以这个元素为分界线,在分别判断两边的序列. 如果只从一遍找的话,最坏的情况是唯一元素在另一头T(n) = T(n-1)+O(n) >= O(n^2)的. 所以应该从两边开始找,T(n) = 2T