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\n",i,len,pre,suf,ans);
}
}
printf("%lld\n",ans);
return 0;
}
/*
10 1
1 3 7 1 9 5 6 8 4 3
*/

【BZOJ-2119】股市的预测 后缀数组的更多相关文章

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

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

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

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

  3. BZOJ 2119: 股市的预测 SA

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

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

    首先要差分+离散化. 然后就是求形如ABA的串有多少,其中B的长度确定为k. 我们用到了设置关键点的思想.我们枚举A的长度L.然后在\(1,1+L,1+L*2,1+L*3...\)设置关键点.然后我们 ...

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

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

  6. ●BZOJ 2119 股市的预测

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2119 题解: 这个题很好的. 首先把序列转化为差分序列,问题转化为找到合法的子序列,使得去除 ...

  7. bzoj 2119 股市的预测 —— 枚举关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119 思路就是对于这个形如 ABA 的串,枚举 A 的长度,并按照长度分出几块,找到一些关键 ...

  8. bzoj 2119 股市的预测——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119 就是找差分序列上中间差 m 的相等的两段. 考虑枚举这样一段的长度 L .可以把序列分 ...

  9. BZOJ 2119: 股市的预测 (Hash / 后缀数组 + st表)

    转博客大法好 自己画一画看一看,就会体会到这个设置关键点的强大之处了. CODE(sa) O(nlogn)→1436msO(nlogn)\to 1436msO(nlogn)→1436ms #inclu ...

随机推荐

  1. Mysql FROM_UNIXTIME效率 VS PHP date()效率 数据说话!

    这几天在做数据统计,有几个统计图的需求是这样的: 按照年.月.日统计订单数量, 比方一年12个月,统计出1月多少订单,二月多少订单,按照这种模式统计. 但是数据库里存放的是 timestamp  的  ...

  2. 移动Web利器transformjs入门

    简介 在过去的两年,越来越多的同事.朋友和其他不认识的童鞋进行移动web开发的时候,都使用了transformjs,所有必要介绍一下,让更多的人受益,提高编程效率,并享受编程乐趣.(当然transfo ...

  3. HTTPS和HTTP的区别

    (转自:http://www.php100.com/html/it/biancheng/2015/0209/8582.html) 总的来说,http效率更高,https安全性更高. 首先谈谈什么是HT ...

  4. JavaScript执行环境

    执行环境(Execution Context,也称为"执行上下文")是JavaScript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其它数据,决定了各自的行为.当Ja ...

  5. iOS---The maximum number of apps for free development profiles has been reached.

    真机调试免费App ID出现的问题The maximum number of apps for free development profiles has been reached.免费应用程序调试最 ...

  6. Windows 批处理设置dns ,解决能上qq不能开网页

    对于windows 7 @echo off netsh interface ip set dns "本地连接" static 114.114.114.114 primary net ...

  7. html img图片等比例缩放

    在img标签里面只设置宽,不设置高,图片就会等比例缩放.

  8. phpStudy2016 配置多个域名期间遇到的问题

    第一步 在C:\Windows\System32\drivers\etc下的hosts文件下添加   第二步   找到Apache 下的httpd.conf  文件 打开,去掉171行前边的#   第 ...

  9. 每天5分钟 玩转OpenStack 目录列表

    最近在学习 OpenStack 的相关知识,一直苦于 OpenStack 的体系庞大以及复杂程度,学习没有进度,停滞不前.偶然机会在 51CTO 上发现了一个热点的专题关于 OpenStack 的,题 ...

  10. javascript判断数组中是否包含某个元素

    //判断数组array中是否包含元素obj的函数,包含则返回true,不包含则返回false function array_contain(array, obj){ for (var i = 0; i ...