BZOJ4059 [Cerc2012]Non-boring sequences

很厉害的题啊……

不过也是道卡常题……

先离散化一下,处理出每个元素前一个和后一个相等的元素

建议用两遍sort离散化,否则容易TLE

然后我们考虑[L,R]的所有子串是否合法,我们考虑从两边向中间找第一个前一个和后一个都不在这个区间里的元素,然后就可以把区间分成两部分递归

即,先判断L是否只出现一次,再判断R,再判断L+1,再判断R-1……

这样的话复杂度是nlogn的

原理的话,你可以把这个过程看成启发式合并的逆过程,即“启发式分裂”

数据组数多,注意不要用memset

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 200010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct data{
    int v;
    int x;
    int p;
};
char xB[1<<15],*xS=xB,*xT=xB;
#define getc() (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline int read()
{
int x=0,f=1;char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
bool cmp1(data x,data y){
    return x.v<y.v;
}
bool cmp2(data x,data y){
    return x.p<y.p;
}
int n;
data a[MAXN];
int tai[MAXN];
int fro[MAXN],nxt[MAXN];
bool jud(int l,int r){
    if(l>r){
        return 1;
    }
    int L=l,R=r;
    while(L<=R){
        if(fro[L]<l&&nxt[L]>r){
            return jud(l,L-1)&jud(L+1,r);
        }
        if(fro[R]<l&&nxt[R]>r){
            return jud(l,R-1)&jud(R+1,r);
        }
        L++;
        R--;
    }
    return 0;
}
int main(){
    int i;
    int tmp;
    scanf("%d",&tmp);
    while(tmp--){
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i].v);
            a[i].p=i;
        }
        sort(a+1,a+n+1,cmp1);
        for(i=1;i<=n;i++){
            a[i].x=a[i-1].x;
            if(i==1||a[i].v!=a[i-1].v){
                a[i].x++;
            }
        }
        sort(a+1,a+n+1,cmp2);
        for(i=1;i<=n;i++){
            nxt[tai[a[i].x]]=i;
            fro[i]=tai[a[i].x];
            tai[a[i].x]=i;
            nxt[i]=n+1;
        }
        printf(jud(1,n)?"non-boring\n":"boring\n");
        for(i=1;i<=n;i++){
    		tai[a[i].x]=0;
        }
    }
    return 0;
}
 
/*
 
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值