Description

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

Input

第一行包含两个整数N、M,分别表示需要统计的总时间以及重现的间隔(B部分的长度)。
接下来N行,每行一个整数,代表每一个时间点的股价。
4≤N≤50000 1≤M≤10 M≤N 所有出现的整数均不超过32位含符号整数。

Output

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

Sample Input

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

Sample Output

6

解题思路:

还是很佩服后缀数组的思维。

这是求一个具有ABA结构的字符串个数。

发现一个性质,如果左右A足够长,

就可以将中间部分左右移动得到新答案。

枚举A的长度L,按L分块,边缘设为关键点。

易知关键点只能被一个串覆盖一次。

只需正反构建后缀数组求Lcp即可。

时间复杂度n(lnn+logn)

代码:

 #include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=;
struct Sa{
int sa[N];
int tmr[N];
int rnk[N];
int has[N];
int str[N];
int hgt[N];
int Rmq[][N];
int lg[N];
int cnt;
int n;
bool Same(int a,int b,int l)
{
if(a+l>n||b+l>n)
return false;
return (rnk[a]==rnk[b])&&(rnk[a+l]==rnk[b+l]);
}
void Insert(int *a,int len)
{
for(int i=;i<=len;i++)
str[i]=a[i];
n=len;
return ;
}
void Reverse(int *a,int len)
{
int j=;
for(int i=len;i;i--)
str[++j]=a[i];
n=len;
return ;
}
void Build(void)
{
for(int i=;i<=n;i++)
lg[i]=lg[i/]+;
for(int i=;i<=n;i++)
has[str[i]]++;
for(int i=;i<=n;i++)
if(has[i])
tmr[i]=++cnt;
for(int i=;i<=n;i++)
has[i]+=has[i-];
for(int i=;i<=n;i++)
{
sa[has[str[i]]--]=i;
rnk[i]=tmr[str[i]];
}
for(int k=;cnt!=n;k<<=)
{
cnt=;
for(int i=;i<=n;i++)
has[i]=;
for(int i=;i<=n;i++)
has[rnk[i]]++;
for(int i=;i<=n;i++)
has[i]+=has[i-];
for(int i=n;i;i--)
if(sa[i]>k)
tmr[sa[i]-k]=has[rnk[sa[i]-k]]--;
for(int i=;i<=k;i++)
tmr[n-i+]=has[rnk[n-i+]]--;
for(int i=;i<=n;i++)
sa[tmr[i]]=i;
for(int i=;i<=n;i++)
if(Same(sa[i],sa[i-],k))
tmr[sa[i]]=cnt;
else
tmr[sa[i]]=++cnt;
for(int i=;i<=n;i++)
rnk[i]=tmr[i];
}
for(int i=;i<=n;i++)
{
if(rnk[i]==)
continue;
int j=std::max(,hgt[rnk[i-]]-);
while(str[i+j-]==str[sa[rnk[i]-]+j-])
hgt[rnk[i]]=j++;
}
for(int i=;i<=n;i++)
Rmq[][i]=hgt[i];
for(int i=;i<=;i++)
for(int j=;j+(<<i)-<=n;j++)
Rmq[i][j]=std::min(Rmq[i-][j],Rmq[i-][j+(<<(i-))]);
return ;
}
int Lcp(int i,int j)
{
i=rnk[i],j=rnk[j];
if(j<i)
i^=j^=i^=j;
i++;
int l=lg[j-i+];
return std::min(Rmq[l][i],Rmq[l][j-(<<l)+]);
}
}S1,S2;
int tmp[N];
int sln[N];
int n,B;
std::map<int,int>M;
int main()
{
//freopen("a.in","r",stdin);
scanf("%d%d",&n,&B);
int cnt=;
for(int i=;i<=n;i++)
scanf("%d",&sln[i]);
for(int i=n;i>=;i--)
sln[i]-=sln[i-];
for(int i=;i<=n;i++)
{
if(M.find(sln[i])==M.end())
M[sln[i]]=++cnt;
tmp[i-]=M[sln[i]];
}
S1.Insert(tmp,n-);
S2.Reverse(tmp,n-);
S1.Build();
S2.Build();
int ans=;
for(int L=;L<=((n-)-B)/;L++)
{
for(int i=;i<=n-;i+=L)
{
int j=i+B+L;
if(j>n-)
continue;
int r=std::min(L,S1.Lcp(i,j));
int l=std::min(L,S2.Lcp(n-i,n-j));
int t=l+r-;
if(t>=L)
ans+=t-L+;
}
}
printf("%d\n",ans);
return ;
}

BZOJ2119: 股市的预测(后缀数组)的更多相关文章

  1. 【BZOJ2119】股市的预测 后缀数组+分块

    [BZOJ2119]股市的预测 Description 墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势.股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰 ...

  2. 【BZOJ-2119】股市的预测 后缀数组

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 334  Solved: 154[Submit][Status][Discuss ...

  3. BZOJ 2119: 股市的预测 [后缀数组 ST表]

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 331  Solved: 153[Submit][Status][Discuss ...

  4. BZOJ 2119 股市的预测 (后缀数组+RMQ)

    题目大意:求一个字符串中形如$ABA$的串的数量,其中$B$的长度是给定的 有点像[NOI2016]优秀的拆分这道题 先对序列打差分,然后离散,再正反跑$SA$,跑出$st$表 进入正题 $ABA$串 ...

  5. bzoj千题计划312:bzoj2119: 股市的预测(后缀数组+st表)

    https://www.lydsy.com/JudgeOnline/problem.php?id=2119 题意:将给定数组差分后,求ABA形式的字串个数,要求|B|=m,|A|>0 1.后缀数 ...

  6. [NOI2016]优秀的拆分&&BZOJ2119股市的预测

    [NOI2016]优秀的拆分 https://www.lydsy.com/JudgeOnline/problem.php?id=4650 题解 如果我们能够统计出一个数组a,一个数组b,a[i]表示以 ...

  7. BZOJ2119 股市的预测 字符串 SA ST表

    原文链接https://www.cnblogs.com/zhouzhendong/p/9069171.html 题目传送门 - BZOJ2119 题意 给定一个股票连续$n$个时间点的价位,问有多少段 ...

  8. bzoj2119 股市的预测

    传送门 感觉智商莫名其妙的就变低了……写这题的时候死活想不出来…… 做法其实不难…… 题目要求形如ABA的串的个数,我们可以枚举A的长度,利用标记关键点的方法统计答案.设枚举到的答案为k,每k个点标记 ...

  9. bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 ...

随机推荐

  1. html5缓存

    HTML5 提供了两种在client存储数据的新方法: localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 这些都是由 coo ...

  2. 智课雅思短语---一、be no exception

    智课雅思短语---一.be no exception 一.总结 一句话总结:…也不例外? …be no exception 1.经济的快速发展? the rapid development of ec ...

  3. git帮助命令

    git帮助命令 零.自己实例 cd D://software/code/PHP/phpStudy/PHPTutorial/WWW/github/m_Orchestrate git checkout - ...

  4. BZOJ 1598 第k短路

    思路: 先反向建图 Dijkstra一遍 求出h数组 再正向建图 A_star一遍 搞定 //By SiriusRen #include <queue> #include <cstd ...

  5. 图解RHEL6从安装光盘中进行yum安装

    图解RHEL6从安装光盘中进行yum安装 导读:我们这里讲的Yum,是Yellow dog Updater, Modified的缩写,可执行程序名为yum,它的理念是使用一个中心仓库(reposito ...

  6. happy Mom ——php mysqli DES加密

    看完<爱你就像爱生命>这本书,真的看出小波哥很有才,跟小波哥比起来,我唯一拿的出手的可能就是我比他的颜值了.想起一句话,人不是因为美丽而可爱,而是因为可爱而美丽.所以我对我的要求是,继续修 ...

  7. VBA 字符串操作(基础篇)

    转自:http://blog.csdn.net/jyh_jack/article/details/2315345 mid(字符串,从第几个开始,长度) 在[字符串]中[从第几个开始]取出[长度个字符串 ...

  8. expr---计算工具

    expr命令是一款表达式计算工具,使用它完成表达式的求值操作. expr的常用运算符: 加法运算:+ 减法运算:- 乘法运算:\* 除法运算:/ 求摸(取余)运算:% 语法 expr(选项)(参数) ...

  9. 详解:Linux Chrony 设置服务器集群同步时间

    导读: Chrony是一个开源的自由软件,像CentOS 7或基于RHEL 7操作系统,已经是默认服务,默认配置文件在 /etc/chrony.conf 它能保持系统时间与时间服务器(NTP)同步,让 ...

  10. 使用 docker 安装多版本的 MySQL

    原文:使用 docker 安装多版本的 MySQL 首先从 docker 官网下载安装 docker. 检查 docker 安装是否成功,出现类似下面的信息就是安装好了 $ docker versio ...