BZOJ 2124 等差子序列 线段树维护哈希
等差子序列
Description
给一个 $ 1 $ 到 $ N $ 的排列 $ (A_i) $ ,询问是否存在 $ 1 \le p_1<p_2<p_3<p_4<p_5<…<p_{Len} \le N (Len \ge 3) $ ,
使得 $ A_{p_1},A_{p_2},A_{p_3},…A_{p_{Len}}是一个等差序列。
Input
输入的第一行包含一个整数 $ T $ ,表示组数。
接下来 $ T $ 组数据,每组第一行一个整数 $ N $ ,每组第二行为一个 $ 1 $ 到 $ N $ 的排列,数字两两之间用空格隔开。
$ N \le 10000,T \le 7 $
Output
对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。
Sample Input
2
3
1 3 2
3
3 2 1
Sample Output
N
Y
思路
-
题目是要找 $ i<j<k $ ,使得 $ A_j - A_i = A_k - A_j $ ;
-
我们考虑按顺序插入 $ (A_i) $ ,对于我们当前位置 $ j $ ,如果有一个 $ A_i $ 已经出现了,
但是 $ A_k $ 还没有出现,因为是排列,所以这个 $ A_k $ 必然在后面,所以答案为“Y”; -
我们用一个辅助数组 $ (B_i) $ ,按顺序如果 $ x $ 出现了,就标记为 $ 1 $ ,
那么如果一个数 $ x $ 满足条件,那么必然有 $ B_{x-y} != B_{x+y} $ ,
那么只需要判断以 $ x $ 为中心的最长的字符串是否为回文串即可; -
因为如果不是回文串那么必然能找到一个 $ B_{x-y} != B_{x+y} $ ,所以答案为“Y”,
判断回文串可以用正反两边 $ hash $ ,然后 $ hash $ 值要动态修改,所以用树状数组和线段树都可以;
代码
/**************************************************************
Problem: 2124
User: PotremZ
Language: C++
Result: Accepted
Time:2480 ms
Memory:2072 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define Mod 1000000007
#define N 10005
inline int read() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
int T,n,a[N],hash1[N<<2],hash2[N<<2],pows[N];
inline void pushup(int o,int len){
int mid=len>>1;
hash1[o]=(hash1[o<<1]*pows[mid]%Mod+hash1[o<<1|1])%Mod;
hash2[o]=(hash2[o<<1]+hash2[o<<1|1]*pows[len-mid]%Mod)%Mod;
}
void updata(int o,int l,int r,int pos){
if(l==r){
hash1[o]=hash2[o]=1;
return;
}
int mid=l+r>>1;
if(pos<=mid) updata(o<<1,l,mid,pos);
else updata(o<<1|1,mid+1,r,pos);
pushup(o,r-l+1);
}
int query1(int o,int l,int r,int L,int R){
if(L>R) return 0;
if(L==l&&r==R) return hash1[o];
int mid=l+r>>1;
if(L>mid) return query1(o<<1|1,mid+1,r,L,R);
else if(R<=mid) return query1(o<<1,l,mid,L,R);
else return (query1(o<<1,l,mid,L,mid)*pows[R-mid]%Mod+query1(o<<1|1,mid+1,r,mid+1,R))%Mod;
}
int query2(int o,int l,int r,int L,int R){
if(L>R) return 0;
if(L==l&&r==R) return hash2[o];
int mid=l+r>>1;
if(L>mid) return query2(o<<1|1,mid+1,r,L,R);
else if(R<=mid) return query2(o<<1,l,mid,L,R);
else return (query2(o<<1,l,mid,L,mid)+query2(o<<1|1,mid+1,r,mid+1,R)*pows[mid-L+1]%Mod)%Mod;
}
signed main(){
T=read(); pows[0]=1;
for(int i=1;i<N;++i) pows[i]=(pows[i-1]<<1)%Mod;
while(T--){
n=read(); bool f=0;
memset(hash1,0,sizeof(hash1));
memset(hash2,0,sizeof(hash2));
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i){
int len=min(n-a[i],a[i]-1);
if(query1(1,1,n,a[i]-len,a[i]-1)!=query2(1,1,n,a[i]+1,a[i]+len)){ puts("Y"); break;}
updata(1,1,n,a[i]);
if(i==n) puts("N");
}
}
return 0;
}