BZOJ 4059: [Cerc2012]Non-boring sequences(启发式分治)

传送门

解题思路

  首先可以想到要预处理一个\(nxt_i\)\(pre_i\),表示前后与当前位置权值相同的节点,那么这样可以迅速算出某个点在某段区间是否出现多次。然后这样的话就考虑分治,对于\([L,R]\)来说,如果当前点\(i\)满足\(nxt_i>R\)\(pre_i<L\),说明这个点在这个区间出现了一次,就可以分治下去。如果暴力枚举时间复杂度承受不住,我们考虑开头枚举一个,结尾枚举一个,这样的话其实就是一个启发式合并的逆过程,时间复杂度\(O(nlogn)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>

using namespace std;
const int N=200005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;  
}

int T,n,a[N],pre[N],nxt[N];
map<int,int> mp;

bool solve(int l,int r){
    if(l>=r) return 1;
    int L=l,R=r,f=0;
    while(L<=R){
        if(!f) {
            if(nxt[L]>r && pre[L]<l) 
                return (solve(l,L-1) && solve(L+1,r));
            L++;
        }
        else {
            if(nxt[R]>r && pre[R]<l)
                return (solve(l,R-1) && solve(R+1,r));
            R--;
        }
        f^=1;
    }
    return 0;
}

int main(){
    T=rd();
    while(T--){
        n=rd(); mp.clear();
        for(int i=1;i<=n;i++){
            pre[i]=0; a[i]=rd();
            if(mp.count(a[i])) pre[i]=mp[a[i]];
            mp[a[i]]=i;
        }
        mp.clear();
        for(int i=n;i;i--){
            nxt[i]=n+1;
            if(mp.count(a[i])) nxt[i]=mp[a[i]];
            mp[a[i]]=i; 
        }
        puts(solve(1,n)?"non-boring":"boring");
    }
    return 0;   
}

转载于:https://www.cnblogs.com/sdfzsyq/p/10301426.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值