• BZOJ 2124:等差子序列


    简要题意:

    给定一个长度为n的排列pi,问是否存在一个长度大于等于3的等差子序列。

    思路:

    首先,很显然的一点,我们只需要考虑是否存在长度等于3的等差子序列即可。

    而且要注意到本题非常特殊的一点是排列,这意味着[1..n]中的每个数都恰好出现一次且仅出现一次。

    那么当我们枚举等差子序列中间的那一项时,不妨设为a[mid],

    那么假设等差子序列的第一项为a[l](l<mid),那么如果2*a[mid]-a[l]>=1 且 2*a[mid]-a[l]<=n,

    那么2*a[mid]-a[l]要么落在mid左侧,要么落在mid右侧。

    如果落在mid右侧,那么长度等于3的等差子序列即存在。

    由于时限的关系,O(n^2)的做法会超时,因此我们显然不能在枚举中间项的同时再枚举第一项;

    因此此时优化的点在于不枚举第一项,而是采用一种替代的方法,不通过枚举来得到我们需要的效果。

    我们需要用一种数据结构来存储在mid左侧出现过的数字。

    并且支持快速查找每一个[1..n]的数字x,2*a[mid]-x是否也同时在这个数据结构中出现。

    如果2*a[mid]-x不在这个数据结构出现,且1<=2*a[mid]-x<=n,说明2*a[mid]-x一定在mid的右侧出现,那么说明此时我们需要的等差子序列出现了。

    这启发我们用权值线段树来完成这个工作,

    我们可以用一个01权值线段树来记录所有出现在mid左侧的数字,即x这个数值出现,则线段树上x的位置的值为1,否则为0;

    那么相当于我们需要判断的是我们的01权值线段树是否关于a[mid]值对称。(当然细节需要注意,超出[1..n]的部分需要丢掉)

    快速判断两个区间是否相同,这就属于字符串hash的功能范围内了。

    因此,我们在权值线段树上同时维护区间从左到右的Hash值,从右到左的Hash值,当查询的时候只需要快速判断一下a[mid]两侧的Hash值是否相同即可。

    如果不同,说明存在我们需要的等差子序列。

    当我们移动mid时,对权值线段树做的修改就是单点修改,比较方便维护两个Hash值的变化。

    至此,本题已经完成。时间复杂度为O(NlogN)。

    #include<bits/stdc++.h>
    #define lson(p) p<<1
    #define rson(p) p<<1|1
    #define rep(i,a,b) for (int i=a;i<b;i++)
    #define per(i,a,b) for (int i=a-1;i>=b;i--)
    #define all(v) (v).begin() (v).end()
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    #define pb push_back
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    typedef double db;
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    clock_t startTime;
    mt19937 mrand(random_device{}());
    const int mod=1e9+7;
    const int maxn=1e4+10;
    int pw[maxn];
    int a[maxn];
    int T,n;
    db getCurrentTime()
    {
        return (db)(clock()-startTime)/CLOCKS_PER_SEC;
    }
    struct node
    {
        int Lhash,Rhash;
        int len;
        int v;
    }b[maxn<<2];
    void pushup(int p)
    {
        b[p].Lhash=(1LL*b[lson(p)].Lhash*pw[b[rson(p)].len]%mod+b[rson(p)].Lhash)%mod;
        b[p].Rhash=(1LL*b[rson(p)].Rhash*pw[b[lson(p)].len]%mod+b[lson(p)].Rhash)%mod;
        b[p].len=b[lson(p)].len+b[rson(p)].len;
    }
    void build(int p,int l,int r)
    {
        if (l==r) {
            b[p].len=1;
            b[p].Lhash=b[p].Rhash=0;
            b[p].v=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(lson(p),l,mid);
        build(rson(p),mid+1,r);
        pushup(p);
    }
    void modify(int p,int l,int r,int pos)
    {
        if (l==r) {
            b[p].v=1;
            b[p].Lhash=b[p].Rhash=1;
            return ;
        }
        int mid=(l+r)>>1;
        if (pos<=mid) modify(lson(p),l,mid,pos);
        else modify(rson(p),mid+1,r,pos);
        pushup(p);
    }
    node getHash(int p,int l,int r,int L,int R)
    {
        if (L>R) {
            node e;
            e.Lhash=e.Rhash=0;
            return e;
        }
        if (L<=l&&r<=R) return b[p];
        int mid=(l+r)>>1;
        if (R<=mid) return getHash(lson(p),l,mid,L,R);
        else if (L>mid) return getHash(rson(p),mid+1,r,L,R);
        else {
            node e1=getHash(lson(p),l,mid,L,R);
            node e2=getHash(rson(p),mid+1,r,L,R);
            node e;
            e.Lhash=(1LL*e1.Lhash*pw[e2.len]%mod+e2.Lhash)%mod;
            e.Rhash=(1LL*e2.Rhash*pw[e1.len]%mod+e1.Rhash)%mod;
            e.len=e1.len+e2.len;
            return e;
        }
    }
    int main()
    {
        pw[0]=1;
        for (int i=1;i<maxn;i++) pw[i]=1LL*pw[i-1]*233%mod;
        scanf("%d",&T);
        while (T--) {
            scanf("%d",&n);
            for (int i=1;i<=n;i++) scanf("%d",&a[i]);
            build(1,1,n);
            bool bo=false;
            for (int i=1;i<=n;i++) {
                int x=min(a[i]-1,n-a[i]);
                node l=getHash(1,1,n,a[i]-x,a[i]-1);
                node r=getHash(1,1,n,a[i]+1,a[i]+x);
                if (l.Rhash!=r.Lhash) {
                    bo=true; break;
                }
                modify(1,1,n,a[i]);
            }
            if (bo) printf("Y
    ");
            else printf("N
    ");
        }
        return 0;
    }
    

      

  • 相关阅读:
    stl(8)常见的算法
    stl(7)几种常见的迭代器
    stl(6)deque容器
    pre_exam_exercise1
    全为1时计算个数,出现0返回0
    COMP9021--7.18
    lecture 5 Basics of Map Algebra
    COMP9021--7.15
    Lecture 4补充
    COMP9021--7.4
  • 原文地址:https://www.cnblogs.com/xyw5vplus1/p/14586343.html
Copyright © 2020-2023  润新知