题目链接:Permutation - 洛谷
考虑在遍历序列中每个数的同时,动态维护一个数组a,a[x]=0表示当前x没出现过,a[x]=1表示当前x已经出现过了,每次修改后还要检查以x位置为中心,延伸到最长位置,这段a的子序列是否为回文串。比如,n=6,考虑当前加入4,令a[4]=1,并且检查a[2~6]是否为回文,如果是回文,说明:
- 3和5都要么已经出现,要么都没出现(也就是要么都在4左边,要么都在4右边)
- 2和6也有同样的结论
所以“暂时没有出现等差数列”。
每次操作都这样维护即可,需要用线段树维护双向hash值,具体见代码。
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a), (i##i)=(b); i<=(i##i); ++i)
#define ROF(i,a,b) for(int i=(a), (i##i)=(b); i>=(i##i); --i)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
#define ull unsigned long long
#define ls o<<1
#define rs o<<1|1
const int N = 5e5+5, mod=1e9+7, bs=131;
int n;
ull pw[N];
struct node{
ull val; int len;
node(ull v=0, int l=0){val=v, len=l;}
}t1[N<<2], t2[N<<2];
node merge(node l,node r){
node res=node(0,0);
res.val = (l.val*pw[r.len]%mod + r.val)%mod;
res.len = l.len+r.len;
return res;
}
void pushup(int o){
t1[o]=merge(t1[ls], t1[rs]); //左右合并
t2[o]=merge(t2[rs], t2[ls]); //右左合并
}
void build(int o,int l,int r){
if(l==r){
t1[o]=t2[o]=node(0,1); //hash值为0,len为1
return;
}
int mid=l+r>>1;
build(ls,l,mid), build(rs,mid+1,r);
pushup(o);
}
void upd(int o,int l,int r,int pos){
if(l==r){
t1[o]=t2[o]=node(1,1); //修改,把该位置1
return;
}
int mid=l+r>>1;
if(pos<=mid) upd(ls,l,mid,pos);
else upd(rs,mid+1,r,pos);
pushup(o);
}
node query1(int o,int l,int r,int x,int y){ //t1的询问
if(x>y) return node(0,0);
if(x<=l && r<=y) return t1[o];
int mid=l+r>>1;
if(y<=mid) return query1(ls,l,mid,x,y);
else if(x>mid) return query1(rs,mid+1,r,x,y);
node L=query1(ls,l,mid,x,y), R=query1(rs,mid+1,r,x,y);
return merge(L,R);
}
node query2(int o,int l,int r,int x,int y){ //t2的询问
if(x>y) return node(0,0);
if(x<=l && r<=y) return t2[o];
int mid=l+r>>1;
if(y<=mid) return query2(ls,l,mid,x,y);
else if(x>mid) return query2(rs,mid+1,r,x,y);
node L=query2(ls,l,mid,x,y), R=query2(rs,mid+1,r,x,y);
return merge(R,L);
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
pw[0]=1; FOR(i,1,5e5) pw[i]=pw[i-1]*bs%mod; //预处理pow数
int T=1; cin>>T;
while(T--){
cin>>n;
build(1,1,n);
FOR(i,1,n){
int x; cin>>x; //输入序列的每个值
upd(1,1,n,x); //x位置从0改为1
int d=min(x-1,n-x); //延伸半径
if(d<=0) continue;
if(query1(1,1,n,x-d,x-1).val != query2(1,1,n,x+1,x+d).val){cout<<"Y\n"; return 0;}
}
cout<<"N\n";
}
// return 0;
}