终焉之排列
终焉之排列
题意:
给定一个序列 \(a\),求有没有点对满足 \(x\leq y \leq z\) ,有 \(a_x+a_z=2a_y\)
分析:
暴力写法当然是记录每个值出现的位置,然后对于每一个 \(a_i\) 向两边进行搜索。
但是 暴力是一种虫豸的写法 ,考虑正解。
我们设 \(h[x]=1/0\) 表示 \(x\) 是否在 \([1,j]\) 中出现/没出现。
取 \(len=min(n-x,x-1)\) ,如果 \(h[x-len \rightarrow x-1]=h[x+len \rightarrow x+1]\) 不相同,则证明有这样的点对。
可能理解起来有点抽象,我们取一组样例:
1 5 2 4 3
- 当进行到第 \(3\) 次循环时,\(h[1 \rightarrow n]\) 可以表示为:
1 1 0 0 1
此时 \(a[i]=2\) ,则 \(len=min(5-2,2-1)=1\) ,则判断 \(h[1]\) 和 \(h[3]\) 是否相同。
不相同,此时的意义是: \(1\) 在 \(2\) 之前出现过,\(3\) 在 \(2\) 之前没出现过,因此 \(2\) 肯定在 \(1,3\) 之间。
- 当进行到第 \(4\) 次循环,\(h[1 \rightarrow n]\) 可以表示为:
1 1 0 1 1
此时 \(a[i]=4\) ,则 \(len=1\) ,判断 \(h[5]\) 和 \(h[3]\) 是否相同:
不相同,此时的意义是 \(5\) 在 \(4\) 之前出现过,\(3\) 在 \(5\) 之前没出现过,因此 \(4\) 肯定在 \(3,5\) 之间。
可以看出,我们每次都这么算一遍,时间复杂度太炸了,因此需要一种数据结构,能够存储这个 \(0/1\) 串。
考虑字符串哈希:每个长度代表一个值,用线段树维护 \([l,r]\) 区间内 哈希值 的正值/反值,用两个数组维护。
判断 区间 \([x-len,x-1]\) 的正哈希值和 \([x+1,x+len]\) 的反哈希值是否相同,也就是区间 \(h[x-len,x-1]\) 和 \(h[x+len,x+1]\) 是否相同。
如果相同,就证明不在中间,否则在中间,输出 \(YES\) 即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5,P=71;
int sum[2][N<<2],a[N],p[N];
int n,m,T;
void modify(int op,int x,int l,int r,int pos){
if(l==r){
sum[op][x]=1; return;
}
int mid=l+r>>1;
if(pos<=mid) modify(op,x<<1,l,mid,pos);
else modify(op,x<<1|1,mid+1,r,pos);
if(op==0) sum[op][x]=sum[op][x<<1]+sum[op][x<<1|1]*p[mid-l+1];
else sum[op][x]=sum[op][x<<1|1]+sum[op][x<<1]*p[r-mid];
}
int query(int op,int x,int l,int r,int L,int R){
if(L<=l&&r<=R){
if(op==0) return p[l-L]*sum[op][x];
else return p[R-r]*sum[op][x];
}
int mid=l+r>>1,res=0;
if(L<=mid) res+=query(op,x<<1,l,mid,L,R);
if(R>mid) res+=query(op,x<<1|1,mid+1,r,L,R);
return res;
}
int main(){
cin>>T;
while(T--){
cin>>n; int flag=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
p[0]=1; for(int i=1;i<=n;i++) p[i]=p[i-1]*P;
memset(sum,0,sizeof(sum));
for(int i=1;i<n-1;i++){
modify(0,1,1,n,a[i]); modify(1,1,1,n,a[i]);
int len=min(n-a[i+1],a[i+1]-1);
if(len==0) continue;
int Front=query(0,1,1,n,a[i+1]-len,a[i+1]-1);
int Back=query(1,1,1,n,a[i+1]+1,a[i+1]+len);
if(Front!=Back){
puts("YES"); flag=1; break;
}
}
if(flag==0) puts("NO");
}
system("pause");
return 0;
}