[线段树+哈希] Codeforces 452F. Permutation

要注意到这是一个排列,1~n每个数都出现一次,不用上这个条件就做不了。

对于一个数 x , 所有的xk, x+k 一定在 x 的同一侧,否则就输出YES 。所以就有了这样的解法:从左到右扫描序列,设当前到 i , 已经把 1 i1 的数都丢到权值线段树中了。若此时 xk, x+k 有一个是1,有一个是0,则说明找到了。也就是只要比较一下权值线段树 a[i] 两侧的两段的哈希值即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define mp(x,y) make_pair(x,y)
#define Fir first
#define Sec second
using namespace std;
typedef unsigned long long uLL;
const uLL maxn=300005,con=2333;
uLL pw[maxn];
struct node{
    uLL h,rh; node* ch[2];
    node(){ ch[0]=ch[1]=0; h=rh=0; }
    void maintain(int len){
        h=ch[0]->h*pw[len-(len+1>>1)]+ch[1]->h;
        rh=ch[1]->rh*pw[len+1>>1]+ch[0]->rh;
    }
} *root;
typedef node* P_node;
void Updata(P_node p,int L,int R,int pos){
    if(pos<L||R<pos) return;
    if(L==R){ p->h=p->rh=1; return; }
    int mid=(L+R)>>1;
    Updata(p->ch[0],L,mid,pos); Updata(p->ch[1],mid+1,R,pos);
    p->maintain(R-L+1);
}
pair<uLL,int> Merge(pair<uLL,int> A,pair<uLL,int> B){ return mp(A.Fir*pw[B.Sec]+B.Fir,A.Sec+B.Sec); }
pair<uLL,int> Query_hsh(P_node p,int L,int R,int qL,int qR){
    if(R<qL||qR<L) return mp(0,0);
    if(qL<=L&&R<=qR) return mp(p->h,R-L+1); 
    int mid=(L+R)>>1;
    return Merge(Query_hsh(p->ch[0],L,mid,qL,qR),Query_hsh(p->ch[1],mid+1,R,qL,qR));
}
pair<uLL,int> Query_rhsh(P_node p,int L,int R,int qL,int qR){
    if(R<qL||qR<L) return mp(0,0);
    if(qL<=L&&R<=qR) return mp(p->rh,R-L+1); 
    int mid=(L+R)>>1;
    return Merge(Query_rhsh(p->ch[1],mid+1,R,qL,qR),Query_rhsh(p->ch[0],L,mid,qL,qR));
}
P_node Build(int L,int R){
    P_node p=new node();
    if(L==R) return p;
    int mid=(L+R)>>1;
    p->ch[0]=Build(L,mid); p->ch[1]=Build(mid+1,R);
    return p;
}
int n,a[maxn];
int main(){
    freopen("cf452F.in","r",stdin);
    freopen("cf452F.out","w",stdout);
    pw[0]=1;for(int i=1;i<=300000;i++) pw[i]=pw[i-1]*con;
    scanf("%d",&n);
    root=Build(1,n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        int len=min(a[i]-1,n-a[i]);
        if(Query_hsh(root,1,n,a[i]-len,a[i]-1).Fir!=Query_rhsh(root,1,n,a[i]+1,a[i]+len).Fir) return printf("YES\n"),0;
        Updata(root,1,n,a[i]);
    }
    printf("NO\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值