【BZOJ2119】股市的预测

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

题解:判断走势的话一定要用到差分,看起来数据规模较大,所以我们再离散化一下。

设B段长度为M,首先我们可以枚举A段的长度L,然后我们每隔连续的L个时间就选择一个关键点,这样做的用意何在?因为A段的长度就是L,所以每一个合法的A段都包含且仅包含一个关键点,所以我们可以枚举关键点,看一下有多少个合法的A段包含它,这样就能保证不重不漏。

具体地,对于关键点i,我们如何知道它被那些合法的A段所包含呢?我们令j=i+L+M,那么我们从i,j向左右拓展,找到最长的相同的段,我们设向左拓展了l,向右拓展了r,即[i-l...i+r]=[j-l,j+r],如果r+l+1大于L,那么答案就加上r+l+2-L。拓展的时候需要将原串的正串和反串都求一遍后缀数组,然后分别求LCP。

但是,为了满足上面黑字的那条性质,我们向左右拓展的时候不能拓展到其它的关键点,即保证l,r<L

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=50010;
typedef long long ll;
int n,m,L,ans;
int Log[maxn],v[maxn];
struct SA
{
int r[maxn],ra[maxn],rb[maxn],st[maxn],sa[maxn],f[maxn][20],h[maxn],rank[maxn];
void getsa()
{
int i,j,k,p,*x=ra,*y=rb;
for(i=0;i<n;i++) st[x[i]=r[i]]++;
for(i=1;i<m;i++) st[i]+=st[i-1];
for(i=n-1;i>=0;i--) sa[--st[x[i]]]=i;
for(j=p=1;p<n;j<<=1,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<m;i++) st[i]=0;
for(i=0;i<n;i++) st[x[y[i]]]++;
for(i=1;i<m;i++) st[i]+=st[i-1];
for(i=n-1;i>=0;i--) sa[--st[x[y[i]]]]=y[i];
for(swap(x,y),x[sa[0]]=0,i=p=1;i<n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++;
}
for(i=1;i<n;i++) rank[sa[i]]=i;
for(i=k=0;i<n-1;h[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
void getf()
{
int i,j;
for(i=1;i<=n;i++) f[i][0]=h[i];
for(j=1;(1<<j)<=n;j++) for(i=0;i+(1<<j)-1<=n;i++) f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
int getlcp(int a,int b)
{
if(b>n||a<0) return 0;
a=rank[a],b=rank[b];
if(a>b) swap(a,b);
a++;
int k=Log[b-a+1];
return min(f[a][k],f[b-(1<<k)+1][k]);
}
}A,B;
struct node
{
ll val;
int org;
}num[maxn];
bool cmp(node a,node b)
{
return a.val<b.val;
}
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void solve(int siz)
{
int i,j,a,b,l,r;
for(i=0;i+L+siz<n;i+=siz)
{
j=i+siz+L;
if(A.r[i]!=A.r[j]) continue;
a=min(siz,A.getlcp(i,j)),b=min(siz-1,B.getlcp(n-i,n-j));
if(a+b>=siz) ans+=a+b+1-siz;
}
}
int main()
{
n=rd(),L=rd();
int i;
v[0]=rd();
for(i=1;i<n;i++) v[i]=rd(),num[i].org=i,num[i].val=v[i]-v[i-1];
sort(num+1,num+n,cmp);
num[0].val=-1ll<<60;
for(i=1;i<n;i++)
{
if(num[i].val>num[i-1].val) m++;
A.r[num[i].org-1]=m,B.r[n-num[i].org-1]=m;
}
m++;
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
A.getsa(),B.getsa(),A.getf(),B.getf(),n--;
for(i=1;i*2+L<=n;i++) solve(i);
printf("%d",ans);
return 0;
}

最新文章

  1. react native 环境配置
  2. 一些ES5的操作数组的方法
  3. 【JavaScript】图片上传预览
  4. What is SPI?
  5. js二维数组与字符串
  6. Transform组件C#游戏开发快速入门
  7. Zabbix的安装与部署---问题处理(php65.6.28 mysqli 报错误 处理)
  8. bzoj 3594 [Scoi2014]方伯伯的玉米田(DP+二维BIT)
  9. OCA读书笔记(12) - 数据库维护
  10. 【LeetCode】419. Battleships in a Board
  11. [iOS]C语言技术视频-05-程序循环结构(do{}while();)
  12. Dockerfile 最佳实践
  13. 例10-1 uva11582(裴波那切数列)
  14. 转 Singleton clr via c#3
  15. sort与uniq命令详解
  16. Anaconda spyder 设置tab键为2个空格
  17. Scala学习之路 (一)Scala的安装
  18. 开源项目MultiChoiceAdapter详解(二)——MultiChoiceArrayAdapter的使用
  19. EXCEL教程,包你一学就会
  20. PHP接口开发加密技术实例原理与例子

热门文章

  1. 今天终于看了一下tanh函数的形式,双曲正切函数
  2. Mac安装pstree
  3. Linux7个runlevel
  4. zookeeper安装和使用
  5. GridView后台绑定数据列表方法
  6. PS如何精确设置参考线,标尺,辅助线
  7. 基于bootstrsp的jquery富文本编辑器的手冊说明
  8. Linux Shell 高级变量及字符串
  9. c# 冒号 :
  10. [redis]redis概述