2119: 股市的预测

Time Limit: 10 Sec   Memory Limit: 259 MB

Submit: 437  

Solved: 202

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位含符号整数。



【分析】

差分离散化一下...就变成了给定一个串,求形如ABA(B长度给定)的子串的个数

枚举A的长度,然后枚举关键点左右扩展。例如当前关键点为i,枚举的长度为j,那么l=i,r=i+j+m(m为给定B的长度)。

然后l和r向左向右扩展,即求lcp和lcs,而且不能扩展到其它关键点,所以lcp=min(lcp,j),lcs=min(lcs,j)。

如果lcp+lcs>j,那么证明左端点在某个区间内的子串都能对答案产生1的贡献。ans+=lcp+lcs-j。



【代码】

//bzoj 2119 股市的预测
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=50005;
struct node {int id;ll p;} c[mxn];
ll ans;
int tmp[mxn];
int n,m,len,cnt;
inline bool yhx(node wxl,node yny)
{
	return wxl.p==yny.p?wxl.id<yny.id:wxl.p<yny.p;
}
inline bool czy(node wxl,node yny)
{
	return wxl.id<yny.id;
}
struct suffix
{
	int st[mxn][30],rank[mxn],height[mxn];
	int a[mxn],b[mxn],x[mxn],y[mxn],sa[mxn];
	inline bool comp(int i,int j,int l)
	{
	    return y[i]==y[j]&&(i+l>len?-1:y[i+l])==(j+l>len?-1:y[j+l]);
	}
	inline void work()
	{
	    int i,j,k,p;m=128;
	    fo(i,0,m) b[i]=0;
	    fo(i,1,len) b[x[i]=a[i]]++;
	    fo(i,1,m) b[i]+=b[i-1];
	    for(i=len;i>=1;i--) sa[b[x[i]]--]=i;
	    for(k=1;k<=len;k<<=1)
	    {
	        p=0;
	        fo(i,len-k+1,len) y[++p]=i;
	        fo(i,1,len) if(sa[i]>k) y[++p]=sa[i]-k;
	        fo(i,0,m) b[i]=0;
	        fo(i,1,len) b[x[y[i]]]++;
	        fo(i,1,m) b[i]+=b[i-1];
	        for(i=len;i>=1;i--) sa[b[x[y[i]]]--]=y[i];
	        swap(x,y),p=2,x[sa[1]]=1;
	        fo(i,2,len)
	          x[sa[i]]=comp(sa[i-1],sa[i],k)?p-1:p++;
	        if(p>len) break;
	        m=p;
	    }
	    p=k=0;
	    fo(i,1,len) rank[sa[i]]=i;
	    for(i=1;i<=len;height[rank[i++]]=k)
	      for(k?k--:0,j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
	}
	inline void init()
	{
	    int i,j;
	    fo(i,1,len) st[i][0]=height[i];
	    fo(j,1,28)
	      fo(i,1,len) if((i+(1<<j)-1)<=len)
	        st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
	}
	inline int lcp(int x,int y)
	{
		x=rank[x],y=rank[y];
	    if(x>y) swap(x,y);
	    x++;
	    int k=0;
	    while(x+(1<<k+1)<=y) k++;
	    return min(st[x][k],st[y-(1<<k)+1][k]);
	}
}A,B;
inline void lsh()
{
	int i,j;
	scanf("%d%d%d",&len,&n,&tmp[1]);
    fo(i,2,len)
    {
        scanf("%d",&tmp[i]);
        c[i-1].p=(ll)tmp[i]-tmp[i-1];
        c[i-1].id=i;
    }len--;
    sort(c+1,c+len+1,yhx);
    fo(i,1,len)
      if(c[i].p!=c[i-1].p || i==1) tmp[i]=++cnt;
      else tmp[i]=tmp[i-1];
    fo(i,1,len) c[i].p=tmp[i];
    sort(c+1,c+len+1,czy);
    fo(i,1,len)
	  A.a[i]=B.a[len-i+1]=c[i].p;
	A.work(),A.init();
	B.work(),B.init();
}
int main()
{
    int i,j;
	lsh(); 
	fo(j,1,len)  //枚举长度 
	  for(i=1;i+j+n<=len;i+=j)
	  {
	  	  int l=i,r=i+j+n;
	  	  int lc=A.lcp(l,r),ls=B.lcp(len-l+1,len-r+1);
	  	  lc=min(lc,j),ls=min(ls,j);
	  	  if(lc+ls>j)
	  	    ans+=lc+ls-j;
	  }
	printf("%lld\n",ans);
    return 0;
}