zoukankan      html  css  js  c++  java
  • 【BZOJ-2119】股市的预测 后缀数组

    2119: 股市的预测

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 334  Solved: 154
    [Submit][Status][Discuss]

    Description

    墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势。股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况。经过长时间的观测,墨墨发现很多股票都有如下的规律:之前的走势很可能在短时间内重现!如图可以看到这只股票A部分的股价和C部分的股价的走势如出一辙。通过这个观测,墨墨认为他可能找到了一个预测股票未来走势的方法。进一步的研究可是难住了墨墨,他本想试图统计B部分的长度与发生这种情况的概率关系,不过由于数据量过于庞大,依赖人脑的力量难以完成,于是墨墨找到了善于编程的你,请你帮他找一找给定重现的间隔(B部分的长度),有多少个时间段满足首尾部分的走势完全相同呢?当然,首尾部分的长度不能为零。

    Input

    输入的第一行包含两个整数N、M,分别表示需要统计的总时间以及重现的间隔(B部分的长度)。接下来N行,每行一个整数,代表每一个时间点的股价。

    Output

    输出一个整数,表示满足条件的时间段的个数

    Sample Input

    12 4
    1 2 3 4 8 9 1 2 3 4 8 9

    Sample Output

    6
    【样例说明】
    6个时间段分别是:3-9、2-10、2-8、1-9、3-11、4-12。

    HINT

    对于100%的数据,4≤N≤50000 1≤M≤10 M≤N 所有出现的整数均不超过32位含符号整数。

    Source

    Solution

    一眼居然没读懂题...

    把题目转化一下,差分后,就是求形如$ABA$的子串数目,其中$|B|=K$

    这样显然就是可以用后缀数组乱搞,最暴力的方法就是依次枚举$B$的初始位置,然后前后匹配,然后统计入答案。

    所以枚举长度,然后对序列分段统计答案。

    具体的就是对于枚举的长度$len$,从$1$开始每次枚举的端点$+len$,同时可以直接求出另一端的位置,然后求两端向前向后扩展的LCP即可。

    问题在于直接利用LCP求答案会出现重复,所以限制当前端点向前向后统计LCP时不得跨越上一个/下一个枚举到的端点,还需要注意的就是向前向后统计时不要两次统计当前端点。

    根据调和级数,这样的枚举的复杂度是$O(NlogN)$,加上后缀数组的$O(NlogN)$,并不影响总复杂度。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define LL long long
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    	return x*f;
    }
    #define MAXN 100010 
    int N,K,a[MAXN];
    int R[MAXN],SA[MAXN],height[MAXN],rank[MAXN],t1[MAXN],t2[MAXN],st[MAXN];
    inline void Sort(int *x,int *y,int *sa,int L,int M)
    {
        for (int i=0; i<=M; i++) st[i]=0;
        for (int i=0; i<L; i++) st[x[y[i]]]++;
        for (int i=1; i<=M; i++) st[i]+=st[i-1];
        for (int i=L-1; i>=0; i--) sa[--st[x[y[i]]]]=y[i];
    }
    inline void DA(int *r,int *sa,int L,int M)
    {
        int *x=t1,*y=t2,*t,i,j,p;
        for (int i=0; i<L; i++) x[i]=r[i],y[i]=i;
        Sort(x,y,sa,L,M);
        for (j=1,p=1; j<L && p<L; j<<=1,M=p-1)
            {
                for (p=0,i=L-j; i<L; i++) y[p++]=i;
                for (i=0; i<L; i++) if (sa[i]>=j) y[p++]=SA[i]-j;
                Sort(x,y,sa,L,M);
                for (t=x,x=y,y=t,i=1,x[sa[0]]=0,p=1; i<L; i++)
                    x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]? p-1:p++;
            }
    }
    inline void Height(int *r,int *sa,int *rank,int *h,int L)
    {
        h[1]=0;
        for (int i=1; i<=L; i++) rank[sa[i]]=i;
        for (int i=1,k=0,j; i<=L; h[rank[i++]]=k)
            for (k? --k:k=0,j=sa[rank[i]-1]; r[j+k]==r[i+k]; k++);
    }
    int log_2[MAXN],dp[MAXN][21];
    inline void St(int L)
    {
        log_2[0]=-1;
        for (int i=1; i<=L; i++) 
            if (i&(i-1)) 
    			log_2[i]=log_2[i-1];
            else 
    			log_2[i]=log_2[i-1]+1;
        for (int i=0; i<=L; i++) dp[i][0]=height[i+1];
        for (int j=1; (1<<j)<=L; j++)
            for (int i=0; i+(1<<j)-1<=L; i++)
                dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
    inline int RMQ(int l,int r) {int k=log_2[r-l]; return min(dp[l][k],dp[r-(1<<k)][k]);}
    inline int LCP(int l,int r) {l=rank[l],r=rank[r]; if (l>r) swap(l,r); return RMQ(l,r);}
    int ls[MAXN];
    int main()
    {
    	N=read(),K=read();
    	for (int i=1; i<=N; i++) a[i]=read();
    	for (int i=1; i<=N-1; i++) ls[i]=R[i]=a[i+1]-a[i];
    	for (int i=1; i<=N-1; i++) R[N+i]=R[N-1-i+1];
    	sort(ls+1,ls+N-1+1);
    	int mx=unique(ls+1,ls+N-1+1)-ls-1;
    //	for (int i=1; i<=2*N-1; i++) printf("%d  ",R[i]); puts("");
    	for (int i=1; i<=2*N-1; i++) R[i]=lower_bound(ls+1,ls+mx+1,R[i])-ls;
    	R[N]=mx+1;
    //	for (int i=1; i<=2*N-1; i++) printf("%d  ",R[i]); puts("");
    	DA(R,SA,2*N-1+1,mx+1); Height(R,SA,rank,height,2*N-1); St(2*N-1);
    	LL ans=0;
    	for (int len=1; len*2+K<=N-1; len++)
    		{
    			int pre=0,suf=0;
    			for (int i=1; i+len+K<=N-1; i+=len)
    				{
    					suf=min(len,LCP(i,i+len+K));
    					if (i>1) pre=min(len-1,LCP(2*N-1-i+1+1,2*N-1-(i+len+K)+1+1)); else pre=0;
    //					printf("%d  %d  %d  %d->",i,i+len+K,2*N-1-i+1,2*N-1-(i+len+K)+1);
    					if (suf+pre>=len) ans+=(LL)(suf+pre-len+1);
    //					printf("%d   %d   %d   %d   %I64d
    ",i,len,pre,suf,ans);
    				}
    		}
    	printf("%lld
    ",ans);
    	return 0;
    }
    /*
    10 1
    1 3 7 1 9 5 6 8 4 3 
    */
  • 相关阅读:
    杀死初创科技公司的四大工程陷阱
    杀死初创科技公司的四大工程陷阱
    Linux中su和sudo的用法整理
    Linux中su和sudo的用法整理
    Docket 使用命令
    Docker 部署 portainer
    Linux 双网卡绑定
    docker安装部署,阿里源加速
    nmcli详解
    搭建LAMP环境示例
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6255347.html
Copyright © 2011-2022 走看看