考虑第
i
位上的数
那么我们从左往右扫这个数列,用权值线段树记录哪些数出现过,那么就是判断区间 [ai−k,ai] 和 [ai,ai+k] 是否对称。
线段树上HASH一下就好了
复杂度 O(nlogn)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long Ull;
const int N=300010;
const Ull P=1000003;
int n,a[N];
Ull p[N],lval[N<<2],rval[N<<2];
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 rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
void Modify(int g,int l,int r,int x){
if(l==r) return lval[g]=rval[g]=1,void();
int mid=l+r>>1;
(x<=mid)?Modify(g<<1,l,mid,x):Modify(g<<1|1,mid+1,r,x);
lval[g]=lval[g<<1|1]+lval[g<<1]*p[r-mid];
rval[g]=rval[g<<1]+rval[g<<1|1]*p[mid-l+1];
}
Ull Queryl(int g,int L,int R,int l,int r){
if(L==l && r==R) return lval[g];
int mid=L+R>>1;
if(r<=mid) return Queryl(g<<1,L,mid,l,r);
else if(l>mid) return Queryl(g<<1|1,mid+1,R,l,r);
return Queryl(g<<1|1,mid+1,R,mid+1,r)+Queryl(g<<1,L,mid,l,mid)*p[r-mid];
}
Ull Queryr(int g,int L,int R,int l,int r){
if(L==l && r==R) return rval[g];
int mid=L+R>>1;
if(r<=mid) return Queryr(g<<1,L,mid,l,r);
else if(l>mid) return Queryr(g<<1|1,mid+1,R,l,r);
else return Queryr(g<<1,L,mid,l,mid)+Queryr(g<<1|1,mid+1,R,mid+1,r)*p[mid-l+1];
}
int main(){
rea(n);
for(int i=1;i<=n;i++) rea(a[i]);
p[0]=1; for(int i=1;i<=n;i++) p[i]=p[i-1]*P;
for(int i=1;i<=n;i++){
Modify(1,1,n,a[i]);
int k=min(a[i]-1,n-a[i]);
if(Queryl(1,1,n,a[i]-k,a[i])^Queryr(1,1,n,a[i],a[i]+k)) return puts("YES"),0;
}
puts("NO");
return 0;
}