• 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;
    }
    
  • 相关阅读:
    Java
    Leetcode 计划
    Java虚拟机
    浅谈 MVP in Android
    【PAT】B1074 宇宙无敌加法器(20 分)
    【PAT】B1076 Wifi密码(15 分)
    【PAT】B1075 链表元素分类(25 分)
    【PAT】B1077 互评成绩计算(20 分)
    【PAT】B1078 字符串压缩与解压(20 分)
    【PAT】B1079 延迟的回文数(20 分)
  • 原文地址:https://www.cnblogs.com/PotremZ/p/9662973.html
Copyright © 2020-2023  润新知