zoukankan      html  css  js  c++  java
  • 暑假D5 [国家集训队]等差子序列(字符串hash)

    题目描述

    给一个1到N的排列{Ai},询问是否存在

    1p1<p2<p3<p4<p5<<pLenN(Len3)

    使得Ap1,Ap2,Ap3,,ApLen是一个等差序列。

    输入格式:

    输入的第一行包含一个整数T,表示组数。

    下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开。

    输出格式:

    对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则输出一行“N”。

    说明

    对于5%的数据,N<=100

    对于30%的数据,N<=1000

    对于100%的数据,N<=10000,T<=7

    题解:

    排列:每个数出现且仅出现一次。

    考虑从左到右枚举等差中项b(数值),在在b左边的数状态记为0,b右边的数状态记为1,。

    考虑如果没有等差数列,那么b+k和b-k在同侧,即同为1或0,可以构成回文串。

    对于回文串的判断,可以用数值hash,正反做一遍即可。

    现在考虑枚举下一个等差中项时,如何利用现在的状态。

    可以用线段树存下正反hash值,每次枚举下一个就单点修改,判断就是区间查询。

    区间合并就是  val左*base^(右区间长度)+val右;

    查询的合并要对查询右边界和右区间边界取min

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    #define ull unsigned long long
    const int maxn=100005;
    const ull base=1000007;
    int T,n;
    int num1,num2,root1,root2;
    int a[maxn],a_pos,a_l,a_r;
    ull b[maxn];
    struct tree{
        ull val;
        int ls,rs;
    }t1[maxn<<2],t2[maxn<<2];
    
    void update1(int rt,int len){
        t1[rt].val=t1[t1[rt].ls].val*b[len]+t1[t1[rt].rs].val;
    }
    
    void build1(int &rt,int l,int r){
        rt=++num1;
        if(l==r){
            t1[rt].val=1;
            return ;
        }
        int mid=(l+r)>>1;
        build1(t1[rt].ls,l,mid);
        build1(t1[rt].rs,mid+1,r);
        update1(rt,r-mid);
    }
    
    void update2(int rt,int len){
        t2[rt].val=t2[t2[rt].ls].val*b[len]+t2[t2[rt].rs].val;
    }
    
    void build2(int &rt,int l,int r){
        rt=++num2;
        if(l==r){
            t2[rt].val=1;
            return ;
        }
        int mid=(l+r)>>1;
        build2(t2[rt].ls,l,mid);
        build2(t2[rt].rs,mid+1,r);
        update2(rt,r-mid);
    }
    
    void modify1(int rt,int l,int r){
        if(l==r){
            t1[rt].val=0;
            return ;
        }
        int mid=(l+r)>>1;
        if(a_pos<=mid) modify1(t1[rt].ls,l,mid);
        else modify1(t1[rt].rs,mid+1,r);
        update1(rt,r-mid);
    }
    
    void modify2(int rt,int l,int r){
        if(l==r){
            t2[rt].val=0;
            return ;
        }
        int mid=(l+r)>>1;
        if(a_pos<=mid) modify2(t2[rt].ls,l,mid);
        else modify2(t2[rt].rs,mid+1,r);
        update2(rt,r-mid);
    }
    
    ull querry1(int rt,int l,int r){
        if(a_l<=l&&r<=a_r) return t1[rt].val;
        int mid=(l+r)>>1;
        if(a_r<=mid) return querry1(t1[rt].ls,l,mid);
        else if(a_l>mid) return querry1(t1[rt].rs,mid+1,r);
        else return querry1(t1[rt].ls,l,mid)*b[min(a_r,r)-mid]+querry1(t1[rt].rs,mid+1,r);
    }
    
    ull querry2(int rt,int l,int r){
        if(a_l<=l&&r<=a_r) return t2[rt].val;
        int mid=(l+r)>>1;
        if(a_r<=mid) return querry2(t2[rt].ls,l,mid);
        else if(a_l>mid) return querry2(t2[rt].rs,mid+1,r);
        else return querry2(t2[rt].ls,l,mid)*b[min(a_r,r)-mid]+querry2(t2[rt].rs,mid+1,r);
    }
    
    void nice(){
        num1=num2=root1=root2=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build1(root1,1,n);
        build2(root2,1,n);
        for(int i=2;i<n;i++){
            a_pos=a[i-1];
            modify1(root1,1,n);
            a_pos=n-a[i-1]+1;
            modify2(root2,1,n);
            ull ret1,ret2;
            int len=min(a[i]-1,n-a[i]);
            if(!len) continue;
            a_r=a[i]-1;a_l=a[i]-len;
            ret1=querry1(root1,1,n);
            a_r=n-a[i];a_l=a_r-len+1;
            ret2=querry2(root2,1,n);
            if(ret1!=ret2) {printf("Y
    ");return ;}
        }
        printf("N
    ");
    }
    
    int main(){
        b[0]=1;
        for(int i=1;i<=100000;i++) b[i]=b[i-1]*base;
        scanf("%d",&T);
        while(T--) nice();
    }
    View Code
  • 相关阅读:
    剑指offer:合并两个排序的链表
    剑指offer:调整数组顺序使奇数位于偶数前面
    剑指offer:链表中倒数第K个结点
    牛客网在线编程:末尾0的个数
    剑指offer7:数值的整数次方
    牛客网在线编程:计算糖果
    牛客网在线编程:求数列的和
    牛客网在线编程:公共字符
    剑指offer7:斐波那契数列
    Qt入门之常用qt控件认知之Button系列
  • 原文地址:https://www.cnblogs.com/sto324/p/11185587.html
Copyright © 2011-2022 走看看