首页 > 代码库 > BZOJ 2119: 股市的预测 [后缀数组 ST表]
BZOJ 2119: 股市的预测 [后缀数组 ST表]
2119: 股市的预测
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 331 Solved: 153
[Submit][Status][Discuss]
Description
墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势。股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况。经过长时间的观测,墨墨发现很多股票都有如下的规律:之前的走势很可能在短时间内重现!如图可以看到这只股票A部分的股价和C部分的股价的走势如出一辙。通过这个观测,墨墨认为他可能找到了一个预测股票未来走势的方法。进一步的研究可是难住了墨墨,他本想试图统计B部分的长度与发生这种情况的概率关系,不过由于数据量过于庞大,依赖人脑的力量难以完成,于是墨墨找到了善于编程的你,请你帮他找一找给定重现的间隔(B部分的长度),有多少个时间段满足首尾部分的走势完全相同呢?当然,首尾部分的长度不能为零。
Input
输入的第一行包含两个整数N、M,分别表示需要统计的总时间以及重现的间隔(B部分的长度)。接下来N行,每行一个整数,代表每一个时间点的股价。
Output
输出一个整数,表示满足条件的时间段的个数
Sample Input
1 2 3 4 8 9 1 2 3 4 8 9
Sample Output
【样例说明】
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
然后,和上题相似的思路,枚举走势相同的长度L,每L设一个关键点
发现对于一个ABA,第一个A一定覆盖且只覆盖一个关键点,
枚举关键点i,i和i+B+L往左往右匹配长度l和r(同样,我的r包括关键点),如果l+r>=L那么这个地方就有l+r-L+1个满足的子串
(i)--L--B--(i+B+L)--L--
为了做到不重复,左右延伸最大长度为L-1
为什么这样就不重复了?我这个煞笔竟然想了好长时间,因为上面的蓝色字体,每个关键点延伸出来的,第一个L一定覆盖了这个关键点,从其他关键点开始的都不覆盖,所以不重复不遗漏
注意:
1.计数排序最后是倒序
2.因为我的r包括关键点,所以最大是L不是L-1
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N=5e4+5,INF=1e9;inline int read(){ char c=getchar();int x=0,f=1; while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f;}int B,s[N],mp[N],tot;int n,m,c[N],t1[N],t2[N];int Bin(int v){ int l=1,r=tot; while(l<=r){ int mid=(l+r)>>1; if(mp[mid]==v) return mid; else if(v<mp[mid]) r=mid-1; else l=mid+1; } return 0;}inline bool cmp(int *r,int a,int b,int j){ return a+j<=n&&b+j<=n&&r[a]==r[b]&&r[a+j]==r[b+j];}int Log[N],Pow[20],mn[N][17];void iniST(){ Pow[0]=1;for(int i=1;i<20;i++)Pow[i]=Pow[i-1]<<1; Log[0]=-1;for(int i=1;i<=n;i++)Log[i]=Log[i/2]+1;}void getST(int mn[N][17],int a[]){ for(int i=1;i<=n;i++) mn[i][0]=a[i]; for(int j=1;j<=Log[n];j++) for(int i=1;i+Pow[j]-1<=n;i++) mn[i][j]=min(mn[i][j-1],mn[i+Pow[j-1]][j-1]);}struct SA{ int sa[N],rnk[N],height[N],mn[N][17]; void getHeight(){ int k=0; for(int i=1;i<=n;i++) rnk[sa[i]]=i; for(int i=1;i<=n;i++){ if(k) k--; if(rnk[i]==1) continue; int j=sa[rnk[i]-1]; while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++; height[rnk[i]]=k; } } void getSA(){ int *r=t1,*k=t2; for(int i=0;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[r[i]=s[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[r[i]]--]=i; for(int j=1;j<=n;j<<=1){ int p=0; for(int i=n-j+1;i<=n;i++) k[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>j) k[++p]=sa[i]-j; for(int i=0;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[r[k[i]]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[r[k[i]]]--]=k[i]; swap(r,k);p=0;r[sa[1]]=++p; for(int i=2;i<=n;i++) r[sa[i]]=cmp(k,sa[i],sa[i-1],j)?p:++p; if(p>=n) break;m=p; } } int lcp(int x,int y){//printf("lcp %d %d\n",x,y); x=rnk[x];y=rnk[y]; if(x>y) swap(x,y);x++;//printf("rnk %d %d\n",x,y); int t=Log[y-x+1];//printf("t %d %d %d\n",t,mn[x][t],mn[y-Pow[t]+1][t]); return min(mn[x][t],mn[y-Pow[t]+1][t]); } void ini(){ getSA();getHeight();getST(mn,height); } void test(){ puts("test"); for(int i=1;i<=n;i++) printf("%d ",s[i]);puts(""); for(int i=1;i<=n;i++) printf("%d ",rnk[i]);puts(""); for(int i=1;i<=n;i++) printf("%d ",sa[i]);puts(""); for(int i=1;i<=n;i++) printf("%d ",height[i]);puts(""); puts(""); }}a,b;int ans;void solve(int L){//printf("sol %d\n",L); for(int i=1;i+B+L<=n;i+=L) if(s[i]==s[i+B+L]){//puts("begin"); int r=a.lcp(i,i+B+L),l=b.lcp(n-i+2,n-i-B-L+2); l=min(l,L-1);r=min(r,L); //printf("ss %d %d %d %d\n",i,i+B+L,l,r); if(l+r>=L) ans+=l+r+1-L;//,printf("hi %d %d\n",i,i+B+L); //puts("end"); }}int main(){ //freopen("in.txt","r",stdin); n=read();B=read(); for(int i=1;i<=n;i++){ s[i]=read(); if(i!=1) mp[++tot]=s[i-1]=s[i]-s[i-1]; } n--; sort(mp+1,mp+1+n); tot=0;mp[++tot]=mp[1]; for(int i=2;i<=n;i++) if(mp[i]!=mp[i-1]) mp[++tot]=mp[i]; for(int i=1;i<=n;i++) s[i]=Bin(s[i]); m=n; iniST(); a.ini();//a.test(); reverse(s+1,s+1+n); b.ini();//b.test(); reverse(s+1,s+1+n); for(int L=1;L+L+B<=n;L++) solve(L); printf("%d",ans);}
BZOJ 2119: 股市的预测 [后缀数组 ST表]