CSU-ACM2017暑期训练3-递推与递归 J - Non-boring sequences

J - Non-boring sequences

UVA1608
题目要判断一个序列是否满足这样的要求:它的所有连续子序列中至少包含一个不重复的数字。满足这样要求的序列称为non-boring的序列,反之称为boring的序列。

求解主要采用了map来辅助得到每个元素左右最近的相等元素的位置。方法即顺序、逆序遍历所给的序列,遍历过程中用map记录上一次遇到某个值时的位置。详细地说,即每进一步判断一次当前值 n 是否存在,若存在,将map中保存的“上次遇到该值的位置 p ”写入 leftNear[] 中的当前位置(若之前 n 并未出现过,就向 leftNear[] 写入越过其左边界的任意数字,例如-1),接着,将 p 用当前位置替代,重复上述操作,即得每个元素左边最近的相等元素所处的位置。同理可得每个元素右边最近的相等元素所处的位置。

接着,使用一个递归函数,判断子区间是否都满足条件。
某个区间 a[0] .. a[n] 是否non-boring可以这样判断:先看整体,若存在元素 a[i] 在序列中只出现一次,可知当前这个大的区间是non-boring的,需要进一步判断其子区间;对其子区间,我们只需取 a[0] .. a[i - 1] 以及 a[i + 1] .. a[n] 进行判断,以此类推,若全部满足non-boring,则说明区间 a[0] .. a[n] 是non-boring的。
这个特征和对它的利用详见 range_check() 函数,可以一目了然。

程序中,使用map做完了准备工作,调用 range_check(0,n) ,返回真输出non-boring,返回假输出boring即可。

#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;
vector<int> myVec, leftNear(200008), rghtNear(200008);
map<int, int> dupliChek;
bool range_check(int left, int rght){
    if(left >= rght)
        return true;
    for(int i = 0; i <= (rght - left) / 2; i++){   //从两边向中间找,提高效率
        if(leftNear[left + i] < left && rghtNear[left + i] > rght)
            return range_check(left, left + i - 1) && range_check(left + i + 1, rght);
        if(leftNear[rght - i] < left && rghtNear[rght - i] > rght)
            return range_check(left, rght - i - 1) && range_check(rght - i + 1, rght);
    }
    return false;
}
int main(){

    int T;
    cin >> T;
    for(int t = 0; t < T; t++){
        myVec.clear();
        int n, temp;
        cin >> n;
        for(int i = 0; i < n; i++){
            scanf("%d", &temp);
            myVec.push_back(temp);
        }
        dupliChek.clear();
        for(int i = 0; i < n; i++){                   //-----+                      
            if(dupliChek.count(myVec[i])){            //     |                               
                leftNear[i] = dupliChek[myVec[i]];    //     |                                       
            }                                         //     |   
            else{                                     //     |       
                leftNear[i] = -1;                     //     |                       
            }                                         //     |   
            dupliChek[myVec[i]] = i;                  //     |                           
        }                                             //     |
        dupliChek.clear();                            //     +--用map辅助找出每个位置前后最近重复元素的过程                         
        for(int i = n - 1; i >= 0; i--){              //     |                                         
            if(dupliChek.count(myVec[i])){            //     |                                         
                rghtNear[i] = dupliChek[myVec[i]];    //     |                                                 
            }                                         //     |             
            else{                                     //     |                 
                rghtNear[i] = n;                      //     |                                 
            }                                         //     |             
            dupliChek[myVec[i]] = i;                  //     |                                     
        }                                             //-----+
        if(range_check(0,n - 1))
            printf("non-boring\n");
        else
            printf("boring\n");
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值