[bzoj2119]股市的預測
阿新 • • 發佈:2019-01-07
2119: 股市的預測
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 256 Solved: 119
[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位含符號整數。
把原來的數差分一下,就變成了求給定
暴力的方法肯定可以列舉
這個做法可以優化一下。
每次在列舉第一個
只是求
時間複雜度:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int N=100010;
LL ans;
int s[N],n,m,o,sa[N],rank[N],height[N],t1[N],t2[N],c[N],st[N][20],Log[N],a[N];
inline int in(){
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;
}
inline bool cmp(int *y,int p,int q,int k){
int o0=(p+k>=n+n+1)?-1:y[p+k];
int o1=(q+k>=n+n+1)?-1:y[q+k];
return o0==o1&&y[p]==y[q];
}
inline void build_sa(int o){
int i,k,*x=t1,*y=t2,p;
for(i=0;i<o;++i) c[i]=0;
for(i=0;i<n+n+1;++i) ++c[x[i]=s[i+1]];
for(i=1;i<o;++i) c[i]+=c[i-1];
for(i=n+n;~i;--i) sa[--c[x[i]]]=i;
for(k=1;k<=n+n+1;k<<=1){
for(p=0,i=n+n+1-k;i<n+n+1;++i) y[p++]=i;
for(i=0;i<n+n+1;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<o;++i) c[i]=0;
for(i=0;i<n+n+1;++i) ++c[x[y[i]]];
for(i=1;i<o;++i) c[i]+=c[i-1];
for(i=n+n;~i;--i) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
o=1;x[sa[0]]=0;
for(i=1;i<n+n+1;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?o-1:o++;
if(o>=n+n+1) break;
}
}
inline void build_height(){
int i,k=0,j;
for(i=0;i<n+n+1;++i) rank[sa[i]]=i;
for(i=0;i<n+n+1;++i){
if(!rank[i]) continue;
k=k?--k:k;
j=sa[rank[i]-1];
while(s[j+k+1]==s[i+k+1]) ++k;
height[rank[i]]=k;
}
memset(st,127/3,sizeof(st));
for(i=0;i<n+n+1;++i) st[i][0]=height[i];
for(j=1;j<=20;++j)
for(i=0;i+(1<<(j-1))<n+n+1;++i)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
for(j=0,i=1;i<=n+n+1;++i){
if((1<<(j+1))<=i) ++j;
Log[i]=j;
}
}
inline int LCP(int x,int y){
if(x>y) swap(x,y);
int k=Log[y-x];++x;
return min(st[x][k],st[y-(1<<k)+1][k]);
}
int main(){
int i,j;
n=in();m=in();--n;
for(i=1;i<=n+1;++i) s[i]=in();
for(i=1;i<=n;++i) s[i]=s[i+1]-s[i];
for(i=n;i;--i) s[n+n+1-i]=s[i];
for(i=1;i<=n+n;++i) a[i]=s[i];
sort(a+1,a+n+n+1);
int size=unique(a+1,a+n+n+1)-a-1;
for(i=1;i<=n;++i)
s[i]=lower_bound(a+1,a+size+1,s[i])-a;
for(i=n+n;i>=n+1;--i)
s[i+1]=lower_bound(a+1,a+size+1,s[i])-a;
s[n+1]=size+1;
build_sa(size+2);
build_height();
int pre,sub;
for(i=1;i+i+m<=n;++i)
for(pre=0,j=1;i+j+m<=n;j+=i){
sub=min(i,LCP(rank[j-1],rank[j+i+m-1]));
if(sub+pre>=i) ans+=(LL)(sub+pre-i+1);
pre=min(i-1,LCP(rank[n+n+2-(j+i-1)-1],rank[n+n+2-(j+i+i+m-1)-1]));
}
printf("%lld\n",ans);
}