题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=844&problem=4483&mosmsg=Submission+received+with+ID+15433551
#include <cstdio>
#include <map>
using namespace std;
// before/next[i]代表与该数字相同的最近的前面/后面数字位置,如果没有为-1/n
int before[200010];
int next[200010];
// array[i]代表第i个数字
int array[200010];
// my_map[x]代表数字x的现在位置
map<int,int> my_map;
int n;
bool check(int begin, int end);
int main()
{
int T;
scanf("%d", &T);
int count = 0;
while(count < T)
{
my_map = map<int,int>();
scanf("%d", &n);
// 读入数据并记录每个位置数字的最近前后相同数字位置
for(int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
array[i] = x;
if(my_map.find(x) == my_map.end())
{
my_map[x] = i;
before[i] = -1;
next[i] = n;
}
else
{
int pre_place = my_map[x];
before[i] = pre_place;
next[i] = n;
next[pre_place] = i;
my_map[x] = i;
}
}
// 检查是否满足条件
if(check(0, n-1))
printf("non-boring\n");
else
printf("boring\n");
count++;
}
}
// 检查是否满足条件
// 检查从array[begin...end]是否符合条件
bool check(int begin, int end)
{
if(end <= begin)
return true;
//从array的头和尾同时遍历,找到只出现一次的元素,并递归检查子序列
int end_place = (begin+end)/2;
// int end_place = end;
for(int i = begin; i <= end_place; i++)
{
if(before[i] < begin && next[i] > end)
return check(begin, i-1) && check(i+1, end);
if(before[end+begin-i] < begin && next[end+begin-i] > end)
return check(begin, end+begin-i-1) && check(end+begin-i+1, end);
}
return false;
}
题目没有想出来,关键的思路是:整个序列如果是non-boring必定存在一个元素只出现一次。找到这个元素后,只需要判断前后的两个子序列是否为non-boring即可。
如果其中一个是boring. 那么整个序列为boring,无需再次判断。