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

来源:互联网 发布:微淘号达人淘宝达人 编辑:程序博客网 时间:2024/06/06 01:05

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;}