zoukankan      html  css  js  c++  java
  • [洛谷P2757][国家集训队]等差子序列

    题目描述:https://www.luogu.org/problemnew/show/P2757

    解析:首先一个显然的性质是如果有一个长度大于等于3的等差子序列那么就一定有一个长度为3的等差子序列,反之如果没有一个长度为3的等差子序列,那么原序列就没有等差子序列。那么现在的问题就转化为了求一个数列中是否有一个长度为3的等差子序列。为了方便表述,后面将长度为3的等差子序列简称为等差数列。由于是3个数,很容易就想到枚举中间位置(其实我没想到)。由于是排列,所以原数列没有重复的数。考虑将中间位置左边的数全部染色成0,中间位置右边的数全部染色成1。发现如果要判断这个中间位置的数能否成为一个等差数列的中项,一定满足以这个数为中心的最长的01串(按权值排序后)一定不是回文的。例如原数列是 5 3 2 1 4,现在mid位置枚举到了3,权值为2,那么这时 01串便是0 0 1 1 1,按权值排序后便变成了1 1 0 1 0。现在要判断 2是否为一个等差数列的中项, 只需要看以2为中心最长的区间(1,3)是否为回文串。显然不是,所以找到了一个等差数列。证明简略证一下:一个以这个数n为中心的等差数列它的第3项一定不超过2*(n-1),因为最小的第一项就是1,最大也超不过2*(n-1)。对于一段区间,如果它不是回文串,即中间右边的数与左边的不一样,即在原数列中不在同一侧,它们3个就组成了一个等差数列。于是原问题转化为了如何快速判断一个字符串是否是回文串,支持修改操作。发现一个会问串正着进行一次Hash和反着进行一次Hash结果是相同的,很容易就想到了用线段树维护Hash值。注意下细节就ok了

    附上代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    typedef unsigned long long ULL;
    const int Base=1331,MAXN=100005;
    int T,n;
    ULL powpow[MAXN];
    int a[MAXN];
    int root=1;
    int lson[2*MAXN],rson[2*MAXN];
    int ll[2*MAXN],rr[2*MAXN];
    ULL sum[2*MAXN][2];//zheng fan
    int ndnum=0;
    struct pii{
        ULL first,second;
        int l,r;
    };
    
    void prework(){
        powpow[0]=1;
        for(int i=1;i<MAXN;i++)
        powpow[i]=powpow[i-1]*Base;
    }
    
    void update(int t){
        sum[t][0]=sum[lson[t]][0]*powpow[rr[rson[t]]-ll[rson[t]]+1]+sum[rson[t]][0];
        sum[t][1]=sum[rson[t]][1]*powpow[rr[lson[t]]-ll[lson[t]]+1]+sum[lson[t]][1];
        ll[t]=ll[lson[t]];rr[t]=rr[rson[t]];
    }
    
    void buildtree(int &t,int l,int r){
        t=++ndnum;ll[t]=l;rr[t]=r;
        if(l==r){
            sum[t][0]=sum[t][1]=1;
            return;
        }
        int mid=(l+r)>>1;
        buildtree(lson[t],l,mid);buildtree(rson[t],mid+1,r);
        update(t);
    }
    
    void modify(int t,int l,int r,int L,int R){
        if(l==r){
            sum[t][0]=sum[t][1]=0;
            return;
        }
        int mid=(l+r)>>1;
        if(L<=mid) modify(lson[t],l,mid,L,R);
        else modify(rson[t],mid+1,r,L,R);
        update(t);
    }
    
    pii get_pii(pii a,pii b){
        pii res;
        res.first=a.first*powpow[b.r-b.l+1]+b.first;
        res.second=b.second*powpow[a.r-a.l+1]+a.second;
        res.l=a.l;res.r=b.r;
        return res;
    }
    
    pii query(int t,int l,int r,int L,int R){
        if(L<=l&&r<=R){
            pii res;
            res.first=sum[t][0];res.second=sum[t][1];
            res.l=l;res.r=r;
            return res;
        } 
        int mid=(l+r)>>1;
        pii lf,rt;
        if(L<=mid)
        lf=query(lson[t],l,mid,L,R);
        if(R>mid)
        rt=query(rson[t],mid+1,r,L,R);
        if(R<=mid) return lf;
        else if(L>mid) return rt; 
        else return get_pii(lf,rt);
    }
    
    void work(){
        buildtree(root,1,n);
        modify(root,1,n,a[1],a[1]);
        bool flag=false;
        for(int mid=2;mid<=n;mid++){
            int L=max(1,2*a[mid]-n),R=min(n,2*a[mid]-1);
            pii res=query(root,1,n,L,R);
            if(a[mid]!=1&&a[mid]!=n&&res.first!=res.second){
                flag=true;
                break;
            } 
            modify(root,1,n,a[mid],a[mid]);
        }
        if(flag) printf("Y
    ");
        else printf("N
    ");
    }
    
    int main(){
        prework();
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++)    
            scanf("%d",&a[i]);
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    java后台打开浏览器代码
    java国际化
    Struts2之action 之 感叹号 ! 动态方法调用
    ssh框架总结之action接收参数的三种方式
    电脑开机过程
    4.18quaternion rotation
    4.2
    "hello,world"lena
    bash 简介
    SCHEDULE
  • 原文地址:https://www.cnblogs.com/JoshDun/p/11186018.html
Copyright © 2011-2022 走看看