等差子序列
等差子序列
等差序列只要找三个数就行
x,y,z
想法枚举中间数y O(n) , 公差 d O(n) 看看y-d和y+d是不是在y的同侧(预处理每个数的pos)
这样就O (n^2) 了
优化枚举d的复杂度
我们可以搞个0/1数组,在y左边的设为1,右边的设为0
然后我们查以 y 为中心的是不是个回文串(是回文串说明找不到等差序列)
然后回文就从y向左和向右存两个hash判断是否一样
01数组存正的和反的两个hash,然后单点修改——线段树维护hash
合并 hash[ls]*base^len(rs)+hash[rs]
提醒——base 要预处理出来,开long long, 反着的hash维护注意
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define int long long
#define mid ((l+r)>>1)
#define ls (p<<1)
#define rs (p<<1|1)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
const int N=40005;
const int mod=2147483647;
int T,n,a[N],len;
int hash1[N],hash2[N];
int base[N];
void merge(int p,int len) {
int m=len>>1;
hash1[p]=(hash1[ls]*base[m]+hash1[rs])%mod;
hash2[p]=(hash2[ls]+hash2[rs]*base[len-m])%mod;
}
void modify(int l,int r,int v,int p) {
if(l==r) {hash1[p]=hash2[p]=1;return;}
if(v<=mid) modify(l,mid,v,ls);
if(v>mid) modify(mid+1,r,v,rs);
merge(p,r-l+1);
}
int query1(int L,int R,int l,int r,int p) {
if(L>R) return 0;
if(L==l&&r==R) return hash1[p];
if(R<=mid) return query1(L,R,l,mid,ls);
else if(L>mid) return query1(L,R,mid+1,r,rs);
else return (query1(L,mid,l,mid,ls)*base[R-mid]+query1(mid+1,R,mid+1,r,rs))%mod;
}
int query2(int L,int R,int l,int r,int p) {
if(L>R) return 0;
if(L==l&&r==R) return hash2[p];
if(R<=mid) return query2(L,R,l,mid,ls);
else if(L>mid) return query2(L,R,mid+1,r,rs);
else return (query2(L,mid,l,mid,ls)+query2(mid+1,R,mid+1,r,rs)*base[mid-L+1])%mod;
}
void clear() {
memset(hash1,0,sizeof(hash1));
memset(hash2,0,sizeof(hash2));
}
signed main() {
T=read();
base[1]=3;
for(int i=2;i<=10000;i++) base[i]=(base[i-1]*3)%mod;
while(T--) {
clear();
n=read();
for(int i=1;i<=n;i++) a[i]=read();
bool flag=0;
for(int i=1;i<=n;i++) {
len=min(a[i]-1,n-a[i]);
if(query1(a[i]-len,a[i]-1,1,n,1)!=query2(a[i]+1,a[i]+len,1,n,1)) {
flag=1;break;
}
modify(1,n,a[i],1);
}
puts(flag?"Y":"N");
}
return 0;
}
啊另解https://www.luogu.com.cn/user/56672