给出
n
≤
1
e
4
n\leq1e4
n≤1e4个数,这些数是
1
−
n
1-n
1−n的一个全排列。然后求问这个排列中是否有一个大于等于
3
3
3项的等差子序列。
实际上就是询问是否存在三项的等差子序列。注意到每个数都是唯一的,而且值域很小。按顺序插入每个数,出现的标记为
1
1
1,未出现的标记为
0
0
0,那么插入当前这个数的时候,
1
1
1必定在此数之前出现,
0
0
0必定在此数之后出现。所以如果当前数为中心的位置存在两个位置为
1
1
1和
0
0
0,那么这样的子序列就存在。
等价于当前数位置为中心的极大对称串是否是回文串,若不是回文串则存在。问题转化为单点修改,和判断区间是否是回文串。
线段树维护正反两个哈希,
O
(
l
o
g
)
O(log)
O(log)修改和查询即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
typedef unsigned long long ull;
const ll INF=LONG_LONG_MAX;
const int N=1e4+7;
const int bs=233;
int a[N],b[N];
ull hs1[N<<2],hs2[N<<2];
ull p[N];
void clear() {
memset(b,0,sizeof(b));
memset(hs1,0,sizeof(hs1));
memset(hs2,0,sizeof(hs2));
}
void pushup(int rt,int l,int mid,int r) {
hs1[rt]=hs1[rt<<1]*p[r-mid]+hs1[rt<<1|1];
hs2[rt]=hs2[rt<<1|1]*p[mid-l+1]+hs2[rt<<1];
}
void modify(int rt,int l,int r,int x) {
if(l==r) {
hs1[rt]=hs2[rt]=1;
return;
}
int mid=(l+r)>>1;
if(x<=mid) modify(rt<<1,l,mid,x);
else modify(rt<<1|1,mid+1,r,x);
pushup(rt,l,mid,r);
}
ull query1(int rt,int l,int r,int L,int R) {
if(R<l||L>r) return 0;
if(L<=l&&r<=R) return hs1[rt]*p[R-r];
int mid=(l+r)>>1;
return query1(rt<<1,l,mid,L,R)+query1(rt<<1|1,mid+1,r,L,R);
}
ull query2(int rt,int l,int r,int L,int R) {
if(R<l||L>r) return 0;
if(L<=l&&r<=R) return hs2[rt]*p[l-L];
int mid=(l+r)>>1;
return query2(rt<<1,l,mid,L,R)+query2(rt<<1|1,mid+1,r,L,R);
}
int main() {
int T;
scanf("%d",&T);
p[0]=1;
for(int i=1;i<=10000;i++)
p[i]=p[i-1]*bs;
while(T--) {
clear();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
bool find=false;
for(int i=1;i<=n;i++) {
modify(1,1,n,a[i]);
int Radius=min(a[i],n-a[i]+1);
int l=a[i]-Radius+1;
int r=a[i]+Radius-1;
if(query1(1,1,n,l,r)!=query2(1,1,n,l,r)) {
find=true;
break;
}
}
if(find) puts("Y");
else puts("N");
}
return 0;
}