zoukankan      html  css  js  c++  java
  • bzoj2119 股市的预测

    bzoj

    题解:

    后缀数组+RMQ

    有一个性质是,若出现ABA形式,且|A|比较大|B|<=m,那么真正的B块端点可以来回滑动。

    因此我们可以正反做两遍后缀数组,利用RMQ求出区间最小值即前缀长。

    然后先枚举|A|,再枚举左边A的端点,这样ABA位置大体确定。

    然后在两个左端点处分别向两端延伸,更新答案。

    时间复杂度O(nlnn)?

    代码:

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 50050
    #define ll long long
    int n,m;
    int a0[N],Log[N];
    struct Pair
    {
        ll x;
        int id;
    }pr[N];
    bool vmp(Pair a,Pair b)
    {
        return a.x<b.x;
    }
    struct node
    {
        int a[N],rank[N],tmp[N],sa[N],hs[N],h[N];
        bool cmp(int i,int j,int k)
        {
            if(i+k>n||j+k>n)return 0;
            return rank[i]==rank[j]&&rank[i+k]==rank[j+k];
        }
        void get_sa()
        {
            int i,cnt=0;
            for(i=1;i<=n;i++)hs[a[i]]++;
            for(i=1;i<=n;i++)if(hs[i])tmp[i]=++cnt;
            for(i=1;i<=n;i++)hs[i]+=hs[i-1];
            for(i=1;i<=n;i++)rank[i]=tmp[a[i]],sa[hs[a[i]]--]=i;
            for(int k=1;cnt!=n;k<<=1)
            {
                for(i=1;i<=n;i++)hs[i]=0;
                for(i=1;i<=n;i++)hs[rank[i]]++;
                for(i=1;i<=n;i++)hs[i]+=hs[i-1];
                for(i=n;i>=1;i--)if(sa[i]>k)tmp[sa[i]-k]=hs[rank[sa[i]-k]]--;
                for(i=1;i<=k;i++)tmp[n-i+1]=hs[rank[n-i+1]]--;
                for(i=1;i<=n;i++)sa[tmp[i]]=i;
                for(i=1,cnt=0;i<=n;i++)tmp[sa[i]]=cmp(sa[i-1],sa[i],k)?cnt:++cnt;
                for(i=1;i<=n;i++)rank[i]=tmp[i];
            }
        }
        void get_h()
        {
            for(int i=1;i<=n;i++)
            {
                if(rank[i]==1)continue;
                for(int j=max(1,h[rank[i-1]]-1);;j++)
                {
                    if(a[i+j-1]==a[sa[rank[i]-1]+j-1])h[rank[i]]=j;
                    else break;
                }
            }
        }
        int st[N][20];
        void get_st()
        {
            for(int i=1;i<=n;i++)st[i][0]=h[i];
            for(int j=1;j<=18;j++)
            {
                for(int i=1;i+(1<<j)-1<=n;i++)
                {
                    st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
                }
            }
        }
        int get_len(int i,int j)
        {
            i=rank[i],j=rank[j];
            if(i>j)swap(i,j);
            i++;
            int LG = Log[j-i+1];
            return min(st[i][LG],st[j-(1<<LG)+1][LG]);
        }
    }p[2];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a0[i]);
        for(int i=2;i<=n;i++)
            Log[i]=Log[i>>1]+1;
        n--;
        for(int i=1;i<=n;i++)
        {
            pr[i].x = 1ll*(a0[i+1]-a0[i]);
            pr[i].id = i;
        }
        sort(pr+1,pr+1+n,vmp);
        ll las;
        for(int k=0,i=1;i<=n;i++)
        {
            if(las!=pr[i].x)
            {
                las = pr[i].x;
                k++;
            }
            p[0].a[pr[i].id]=k;
        }
        for(int i=1;i<=n;i++)p[1].a[i]=p[0].a[n-i+1];
        p[0].get_sa(),p[0].get_h(),p[0].get_st();
        p[1].get_sa(),p[1].get_h(),p[1].get_st();
        int ans = 0;
        for(int len = 1;2*len+m<=n;len++)
        {
            for(int i=1;i+m+len<=n;i+=len)
            {
                int j = i+m+len;
                int l1 = min(p[0].get_len(i,j),len);
                int l2 = min(p[1].get_len(n-i+1,n-j+1),len);
                int tmp=l1+l2-(l1&&l2);
                if(tmp-len>=0)ans+=tmp-len+1;
            }
        }
        printf("%d
    ",ans);
        return 0;    
    }
  • 相关阅读:
    jQuery检测滚动条(scroll)是否到达底部
    sql group by
    hbm.xml 详解总结
    net.sf.json 时间格式的转化
    经典SQL语句大全
    HashTable
    in与exist , not in与not exist 的区别
    网页布局常用的一些命名规则和书写
    什么是SOA?
    sql之left join、right join、inner join的区别
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10092512.html
Copyright © 2011-2022 走看看