您的位置:首页 > 产品设计 > UI/UE

UVALive 6258 Non-boring sequences

2017-10-15 22:38 489 查看

Problem

icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4269

vjudge.net/contest/191053#problem/D

Meaning

一个序列,如果它的任意一个连续子序列(子串)都含有一个出现且仅出现一次的数字,那么它是
non-boring
的,否则是
boring
的。

给一个序列,问它是
non-boring
还是
boring


Analysis

如果整个序列存在一个出现且仅出现一次的数,那么任何带上这个数字的子串就都是
non-boring
的,于是以这个数为分界点,把序列分成左右两半,两边又是同样的子问题,分治处理。

对于找这样的分裂点,其实就是找一个上一次出现在区间左端点外、下一次出现在区间右端点外的数,可以预处理出来每个位置,该位置的上一次和下一次出现的位置。

这样的分裂点可能有多个,为了减少递归层数,讲道理应该尽量选一个靠中间的分裂点?(就像快排的那个 pivot)。但是,从中间往两边找超时了,从两边往中间找却不会…

Code

#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 200000;

int seq[N+1], dsc[N+1], tmp[N+1], pre[N+1], nxt[N+1];

bool dfs(int l, int r)
{
if(l >= r)
return true;
/*--- 谜之超时 <- 从中间往两边找
for(int ul = l + r >> 1, ur = ul; l <= ul || ur <= r; --ul, ++ur)
if(l <= ul && pre[ul] < l && r < nxt[ul])
return dfs(l, ul - 1) && dfs(ul + 1, r);
else if(ur <= r && pre[ur] < l && r < nxt[ur])
return dfs(l, ur - 1) && dfs(ur + 1, r);
---*/
for(int ul = l, ur = r; ul <= ur; ++ul, --ur)
if(pre[ul] < l && r < nxt[ul]) // 若 ul 为可行分裂点
return dfs(l, ul - 1) && dfs(ul + 1, r);
else if(pre[ur] < l && r < nxt[ur]) // 若 ur 为可行分裂点
return dfs(l, ur - 1) && dfs(ur + 1, r);
return false;
}

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", seq+i);
dsc[i] = seq[i];
}

// 离散化
sort(dsc + 1, dsc + n + 1);
int m = unique(dsc + 1, dsc + n + 1) - dsc;
for(int i = 1; i <= n; ++i)
seq[i] = lower_bound(dsc + 1, dsc + m, seq[i]) - dsc;

// 上一次出现位置
for(int i = 0; i < m; ++i)
tmp[i] = 0;
for(int i = 1; i <= n; ++i)
{
pre[i] = tmp[seq[i]];
tmp[seq[i]] = i;
}
// 下一次出现位置
for(int i = 0; i < m; ++i)
tmp[i] = n + 1;
for(int i = n; i > 0; --i)
{
nxt[i] = tmp[seq[i]];
tmp[seq[i]] = i;
}

if(dfs(1, n))
puts("non-boring");
else
puts("boring");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: