[ 分治 复杂度分析 ] [ Cerc2012 ] BZOJ4059 Non-boring sequences

本文介绍了一种基于分治思想的算法实现,通过枚举区间中只出现一次的元素进行递归分解,最终判断整个区间的合法性。算法采用了启发式合并的逆过程优化,实现了O(nlogn)的时间复杂度。

对于区间 [l,r][l,r] ,如果 aiai 在区间内只出现了一次,那么跨过 aiai 的区间一定是合法的,只需要判断 [l,i1][l,i−1][i+1,r][i+1,r] 就好了。
这样就得到了一个分治的做法:每次枚举区间中一个点,如果在区间中只出现过一次就分治下去。
有一个优化:把枚举顺序变成每次左边枚举一个点、右边枚举一个点。
然后算下复杂度:

T(n)=max{T(k)+T(nk)+min(k,nk)}T(n)=max{T(k)+T(n−k)+min(k,n−k)}

可以看成启发式合并的逆过程,复杂度为 O(nlogn)O(nlog⁡n)
#include<bits/stdc++.h>
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
const int N=200010;
int k,n,m,T;
int a[N],lst[N],nxt[N];
int c[N<<2];
map<int,int>M;
bool Check(int l,int r){
    if(l>=r)return 1;
    int p1=l,p2=r;
    bool b=0;
    while(p1<=p2){
        if(!b){
            if(lst[p1]<l&&nxt[p1]>r)return Check(l,p1-1)&&Check(p1+1,r);
            p1++;
        }else{
            if(lst[p2]<l&&nxt[p2]>r)return Check(l,p2-1)&&Check(p2+1,r);
            p2--;
        }
        b^=1;
    }
    return 0;
}
int main(){
    Read(T);
    while(T--){
        Read(n);M.clear();
        for(int i=1;i<=n;i++){
            Read(a[i]);
            lst[i]=M[a[i]];M[a[i]]=i;
        }
        M.clear();
        for(int i=n;i;i--){
            nxt[i]=M[a[i]];M[a[i]]=i;
            if(!nxt[i])nxt[i]=n+1;
        }
        puts(Check(1,n)?"non-boring":"boring");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值