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

题目:

如果一个序列的任意连续的子序列中至少有一个只出现一次的元素,则称这个序列是不无聊的。输入一个n(n≤200000)个元素的序列A(各个元素均为109以内的非负整数),判断它是不是不无聊的。

思路:

分治法,平常确实用的非常的少,这次借这个题目熟悉一下。代码思路是学习的紫书上的代码的。

在[L,R]范围内枚举是唯一的数,从这个数的左右两边开始判断是不是左右两边的序列都符合唯一性条件。(包含这个唯一数的区间都是符合条件的,所以只要在从两边开始枚举就可以了。)

代码:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define MAX 1e3
#define FRE() freopen("in.txt","r",stdin)
#define FRO() freopen("out.txt","w",stdout)
using namespace std;
typedef long long ll;
const int maxn = 200005;
int pre[maxn],nxt[maxn],a[maxn];
map<int,int> mp;
int n;

bool isUnion(int pos,int L, int R){//检查在L、R的范围内pos上的数是不是唯一的
    return pre[pos]<L && nxt[pos]>R;
}

bool check(int L,int R){
    if(L>=R) return true;//如果能达到中点,表示都符合条件
    for(int i=0; L+i <= R-i; i++){//枚举L、R之间所有的点,看这个点的两边是不是都符合条件
        if(isUnion(L+i,L,R)) return check(L,L+i-1)&&check(L+i+1,R);//从左边开始枚举
        if(i+L==R-i) break;
        if(isUnion(R-i,L,R)) return check(L,R-i-1)&&check(R-i+1,R);//从右边开始枚举
    }
    return false;
}

int main(){
    //FRE();
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0; i<n; i++){
            scanf("%d",&a[i]);
        }
        mp.clear();
        for(int i=0; i<n; i++){//pre[i]表示位置i上的数左边与之相同的数的位置
            if(!mp.count(a[i])){
                pre[i] = -1;
            }else{
                pre[i] = mp[a[i]];
            }
            mp[a[i]] = i;
        }
        mp.clear();
        for(int i=n-1; i>=0; i--){//nxt[i]表示位置i上的数右边与之相同的数的位置
            if(!mp.count(a[i])){
                nxt[i] = n;
            }else{
                nxt[i] = mp[a[i]];
            }
            mp[a[i]] = i;
        }
        if(check(0,n-1)){
            printf("non-boring\n");
        }else{
            printf("boring\n");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/sykline/p/10345439.html

时间: 2024-10-12 07:10:59

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:11129 - An antiarithmetic permutation(分治法)

题目:11129 - An antiarithmetic permutation 题目大意:求n的反算术级数.就是排序0 ..n - 1 要求不存在长度大于2的序列.例如:5的序列排列后(0, 5, 4, 3, 1, 2) ,但是(0,1,2)是一个等差序列,同样的还有(5,4,3), (5,3,1)... 解题思路:这题需要找到排列的策略:将整个序列分成差不多等长的两个部分,使得左右两部分各自成为等差数列,这样左边的数和右边的数组合就一定不会出现等差数列.然后把这个作为子问题,递归求解.递归到

UVA 11582 - Colossal Fibonacci Numbers!(数论)(分治法幂取模)

巨大的斐波那契数! 题目大意:斐波那契数列f[N],给你a,b,n,求f[a^b]%n. 思路:数论题.f[a^b]%n是有周期的,我们求出来这个周期后就可以将简化成f[(a%周期)^b]%周期运用分治法幂取模. 注意用unsigned long long(貌似是 long long的二倍),不然会溢出,又学了一招... 不知道哪的bug,一直改不对,一直,后来捡来别人的和自己一样的代码一改就对了,,, #include<iostream>//UVA #include<cstdio>

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

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

专题:分治法

分治法(Divide and Conquer) 作为五大算法之一的分治法,可算是最早接触的一种算法.分治法,与其说是一种算法,不如将其称为策略来的更贴切一些.算法的思想就是将大问题分成小问题,并解决小问题之后合并起来生成大问题的解. 分治法的精髓: 分--将问题分解为规模更小的子问题: 治--将这些规模更小的子问题逐个击破: 合--将已解决的子问题合并,最终得出“母”问题的解: 分治法的作用,自然是让程序更加快速地处理问题.比如一个n的问题分解成两个n/2的问题,并由两个人来完成,效率就会快一些

分治法(一)

这篇文章将讨论: 1) 分治策略的思想和理论 2) 几个分治策略的例子:合并排序,快速排序,折半查找,二叉遍历树及其相关特性. 说明:这几个例子在前面都写过了,这里又拿出来,从算法设计的策略的角度把它们放在一起来比较,看看分治是如何实现滴.由于内容太多,我将再花一篇文章来写4个之前没有写过的分治算法:1,大整数乘法   2,矩阵乘法的分治策略   3,最近点对  4,凸包问题,请见下一篇. 好了,切入正题. --------------------------------------------

分治法

分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同.递归的解这些子问题,然后将各子问题的解合并得到原问题的解. 分治法所能解决的问题一般具有以下几个特征: 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质. 3) 利用该问题分解出的子问题的解可以合并为该问题的解: 4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题. 分治法的基本步骤:分治法在

算法实验:分治法合并排序(C++)

这篇文章分两部分来写,第一部分写代码的实现过程,第二部分把实验报告从头到尾呈现出来. 我习惯调试使用的编译器是DEV C++,不是vs系列的,可能头文件上有点区别.但是下面的报告是我放到vs里面测试过的,可以直接用,不影响. 第一部分:(解析) 题目:随机产生一个整型数组,然后用合并排序将该数组做升序排列,要求输出排序前和排序后的数组. 题目分析: 需要随机产生一个整数数组: 采用的算法是合并排序,也就是用归并排序: 输出排序后的数组. 随机产生一个整数数组:这个问题首先想到的是用rand()函

分治法与递归编程步骤

分治法是一种很强大的算法设计方法.基本思想是:将原问题分解为几个规模小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 在分治策略中,递归地求解一个问题,在每层递归中应用如下三个步骤: (1)分解(Divide):将原问题分解为一些子问题,子问题的形式与原问题一样,只是规模更小. (2)解决(Conquer):递归地解出子问题.如果子问题规模足够小,则停止递归,直接求解. (3)合并(Combine):将子问题的解组合成原问题的解. 分治思想体现在编码上,