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

一、题目概述

二、题目释义

要求序列s的所有子序列,若所有这些子序列中均存在一个自己序列内是唯一的数,则称这个序列s是不无聊的

三、思路分析

从序列s开始考虑,序列s的整个长度为n,若序列s中存在一个唯一数,则所有包含了这个数的子序列都是不无聊的,那么有可能不满足的要求的子序列只会存在于这个唯一数的左区间与有区间,那么问题就被分冶为了看左区间与右区间内是否有一个唯一数,若找到了,则继续这样递归下去,直到靠近区间长度为1为止

那么我们怎么样做到快速的查找在区间【l,r】内存在着唯一数呢,我们容易想到可以从两端向中间遍历,这样可以将复杂度整体 / 2,但是我们还缺少一个找到唯一数的办法,遍历只是纯粹的搜索并不能帮助我们判断,那么这么判断呢,用数组来保存?不存在的(手动滑稽)。这里可以有一个非常巧妙的预处理,我们当我们找到一个唯一数时,我们总是去继续检索它的左右区间,也就意味着这个唯一数是在它的左区间不曾出现过,在它的右区间也不曾出现过,那么我们可以为序列s的每一个 i 设置两个表示它们的左右区间是否有和它一样的数 pre[] 与 nex[],若没有则左区间记为一个极小数,右区间则记录为一个极大数,若存在则记录那个最靠近它的数的位置。这个记录过程可以由map映射来完成。

四、AC代码

#include <iostream>
#include <cstdio>
#include <map>

using namespace std;
const int N = 2e5+5;

int a[N];
int pre[N],nxt[N];
map<int,int> mp;

inline bool is_unique(int p,int l,int r)
{
    return pre[p]<l && nxt[p]>r;
}

bool check(int l, int r)
{
    if(l>=r) return 1;
    for(int d=0; l+d<=r-d; d++)
    {
        if(is_unique(l+d,l,r))
            return check(l,l+d-1) && check(l+d+1,r);

        if(l+d == r-d) return 0;

        if(is_unique(r-d,l,r))
            return check(l,r-d-1) && check(r-d+1,r);
    }
    return 0;
}

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        int flag = 0;
        mp.clear();
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[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--)
        {
            if(!mp.count(a[i]))
                nxt[i] = n;
            else
                nxt[i] = mp[a[i]];
            mp[a[i]] = i;
        }
        for(int i=1; i<n; i++)
        {
            if(a[i] == a[i-1])
            {
                flag = 1;
                break;
            }
        }
        if(flag) printf("boring\n");
        else
        {
            if(check(0,n-1)) printf("non-boring\n");
            else printf("boring\n");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/EcliWalker/p/8353033.html

时间: 2024-10-07 00:32:51

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)的.而如果从两头

分冶算法思想

1.分冶算法思想是将一个计算复杂的问题分为规模较小,计算简单的问题,,然后综合各个小问题得到最终问题的答案. 2.分冶算法的执行过程 对于一个对魔为N的问题,若该问题可以容易的解决,则直接解决,否则执行下面的步骤. 将该分解为M个规模较小的子问题,子问题相互独立,并且与原问题形式相同. 递归的解这些问题, 然后,将各子问题的姐合并得到原问题的解. 3.分冶算法例子 java实现: package com.sjx.test1;import java.util.Scanner; public cla

hdu 5314 Happy King 树点分冶 树状数组

Happy King Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 434    Accepted Submission(s): 79 Problem Description There are n cities and n?1 roads in Byteland, and they form a tree. The citie

poj1741 Tree 树的点分冶

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 13528   Accepted: 4350 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an

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

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

1608 - Non-boring sequences(折半递归。。暂且这么叫吧)

该题给一个序列,让我们判断是不是不无聊序列(如果不明白请看样例), 我们可以将区间从大到小不断压缩来确定答案,首先要确定一个区间是否满足要求,只要看这个区间里是不是有一个只出现一次的数,受前面<唯一的雪花>一题的启发,我们可以在O(n)时间内求出当前数离他最近的与他相同的数的位置,用数组保存,那么可以在O(1)的时间快速判断,这样就将时间复杂度降到O(n^2) 但是这样还是不够的,会超时. 紫书上给出了一个很巧妙的方法,那就是在递归的时候折半枚举   , 时间复杂度变成了 T(n) = 2*T

●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]的子区间. 所以继续递归处理上面两个区间即可. (判断某个元素是否在区间里只出现一次,只需考虑它左边第一个与它相同的元素或它右边第一个相同的

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

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