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. [Java开发之路](6)File类的使用

    1. 构造方法 构造方法 描写叙述 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建一个新的文件实例. File(String parent , String ...

  2. FragmentActivity+FragmentTabHost+Fragement替代TabActibvity+TabHost+Activity

    自Android3.2之后,TabActibvity被弃用(Deprecated).取而代之的是FragmentActivity.由于Fragment比Activiy更灵活.消耗的资源更小.全然可以满 ...

  3. HDU 5889 Barricade (Dijkstra+Dinic)

    思路: 首先 先Dijkstra一遍 找出来最短路 不是最短路上的边都不要 然后呢 套个Dinic模板就好了-- 求个最小割 输出 大功告成~~ //By SiriusRen #include < ...

  4. 【Henu ACM Round #13 E】Spy Syndrome 2

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 对m个串建立一棵字典树. 然后对主串. 尝试从第一个位置开始.在字典树中尝试匹配 如果匹配到了位置i 就再从位置i+1开始尝试匹配 ...

  5. visualvm监控tomcat

    https://my.oschina.net/weidedong/blog/787203

  6. snmpd修改端口

    http://blog.csdn.net/cau99/article/details/5077239 http://blog.csdn.net/gua___gua/article/details/48 ...

  7. cogs 1430. [UVa 11300]分金币

    1430. [UVa 11300]分金币 ★☆   输入文件:Wealth.in   输出文件:Wealth.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 圆桌旁坐着 ...

  8. 从零開始的Android新项目7 - Data Binding入门篇

    Data Binding自从去年的Google I/O公布到至今,也有近一年的时间了.这一年来,从Beta到如今比較完好的版本号.从Android Studio 1.3到如今2.1.2的支持,能够说D ...

  9. Linux中配置网桥

    使用kvm虚拟机时,有时候需要自己添加网桥供guest使用. 不使用libvirt来管理的话,可以使用以下方法创建网桥并绑定到物理网卡(RHEL6/Fedora已实验): 1.创建网桥配置文件ifcf ...

  10. Image-Loader LruMemoryCache

    这段时间在研究Universal-Image-Loader 这个图片处理开源框架,这里主要分析一下它的LRU(Least Resently Used,最近最少使用算法)内存缓存的实现. 在UIL它提供 ...