BZOJ 2124 等差子序列 线段树维护哈希

$ \Rightarrow $ 戳我进BZOJ原题

等差子序列

Time Limit: 3 Sec $ \quad $ Memory Limit: 259 MB
 

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;
}
posted @ 2018-09-17 16:43  potrem  阅读(112)  评论(0编辑  收藏  举报