1. 程式人生 > >bzoj 2119 股市的預測

bzoj 2119 股市的預測

字尾陣列好題。

 

差分不用說了。統計形如ABA的數量。

按照什麼順序統計答案呢?

 

列舉B的左端點?但是位置連續,並不代表sa的位置連續,所以難以往兩邊統計A部分的貢獻。

我們轉而列舉A的長度和起始位置,直接這樣做是O(n^2)的。考慮加速

 

正反做兩遍SA,RMQ預處理min,便於O(1)查詢lcp

列舉A的部分長度為L

我們每L個點設定一個關鍵點,

列舉每一個關鍵點i,另一個點j=i+L+B,設i,j兩側匹配的長度(lcp) 為l,r

那麼,如果有l+r>=L,那麼意味著在這裡有l+r-L+1的長度為L的A部分可以做出貢獻

為了不重不漏,l,r的長度和L取min,這樣可以發現,相鄰的(i,j)的起始點沒有公共部分。

如果一個A部分滿足匹配,那麼一定能被一組(i,j)恰好覆蓋一次。

 

至於為什麼列舉L,再間隔L設定關鍵點,是因為長度至少是L的情況下,這樣一定不重不漏。

如果間隔過大,那麼可能中間漏掉一些,如果不和L取min,把上界放寬,可能會重複或者遺漏。

間隔過小,和L取min也會重複,而且本身列舉次數增多還會TLE

 

由於L的限制,使得每一個部分最少長度要有L,所以每相鄰L個位置一次統計,一定不會有遺漏。

說白了,就是用了一個trick,在O(nlogn)的時間內,不重不漏統計了答案。

 

畫一畫圖,細節處理好,就沒了。

#include<bits/stdc++.h>
#define
reg register int #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(ll &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); }
namespace Miracle{ const int N=50005; ll n,m; int lg[2*N]; struct hou{ ll s[N]; int x[N],y[N],c[N],sa[N],rk[N],hei[N]; int f[N][18]; void SA(){ int m=50002; for(reg i=1;i<=n;++i) ++c[x[i]=s[i]]; for(reg i=2;i<=m;++i) c[i]+=c[i-1]; for(reg i=1;i<=n;++i) sa[c[x[i]]--]=i; for(reg k=1;k<=n;k<<=1){ int num=0; for(reg i=n-k+1;i<=n;++i) y[++num]=i; for(reg i=1;i<=n;++i){ if(sa[i]-k>=1) y[++num]=sa[i]-k; } for(reg i=1;i<=m;++i) c[i]=0; for(reg i=1;i<=n;++i) ++c[x[i]]; for(reg i=1;i<=m;++i) c[i]+=c[i-1]; for(reg i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0; for(reg i=1;i<=n;++i){ swap(x[i],y[i]); } num=1; x[sa[1]]=1; for(reg i=2;i<=n;++i){ x[sa[i]]=(y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+k]==y[sa[i-1]+k])?num:++num; } m=num; if(num==n) break; } } void HEI(){ for(reg i=1;i<=n;++i) rk[sa[i]]=i; int k=0; for(reg i=1;i<=n;++i){ if(k) --k; if(rk[i]==1) continue; int j=sa[rk[i]-1]; while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) ++k; hei[rk[i]]=k; } } void build(){ SA();HEI(); // cout<<" nn "<<n<<endl; for(reg i=1;i<=n;++i) f[i][0]=hei[i];//,cout<<f[i][0]<<" "; // cout<<endl; for(reg j=1;j<=17;++j){ for(reg i=1;i+(1<<j)-1<=n;++i){ f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } int query(int x,int y){ // cout<<" query "<<x<<" "<<y<<endl; if(x==y) return n-x+1; x=rk[x],y=rk[y]; if(x>y) swap(x,y); // cout<<" rk "<<x<<" "<<y<<endl; ++x; int len=lg[y-x+1]; // cout<<" min "<<f[x][len]<<" "<<f[y-(1<<len)+1][len]<<endl; int ret=min(f[x][len],f[y-(1<<len)+1][len]); return ret; } }A,B; ll a[N],b[N],cnt; int main(){ rd(n);rd(m); for(reg i=1;i<=n;++i) rd(a[i]); for(reg i=n;i>=1;--i) a[i]-=a[i-1],b[++cnt]=a[i]; sort(b+1,b+cnt+1); cnt=unique(b+1,b+cnt+1)-b-1; for(reg i=1;i<=n;++i) { a[i]=lower_bound(b+1,b+cnt+1,a[i])-b; if(i!=1)A.s[i-1]=a[i],B.s[n-i+1]=a[i];//warning!! n-1-i+1 } // for(reg i=1;i<=n;++i){ // cout<<a[i]<<" "; // }cout<<endl; --n;//warning !! --n // for(reg i=1;i<=n;++i){ // cout<<A.s[i]<<" "; // }cout<<endl; // for(reg i=1;i<=n;++i){ // cout<<B.s[i]<<" "; // }cout<<endl; A.build();B.build(); lg[0]=0; for(reg i=1;i<=n;++i) lg[i]=(i>>(lg[i-1]+1))?lg[i-1]+1:lg[i-1]; ll ans=0; for(reg L=1;L<=n;++L){ // cout<<" L -----------------"<<L<<endl; for(reg i=1;i<=n;i+=L){ int j=i+m+L; if(j>n) break; // cout<<"ii ******* "<<i<<" "<<j<<endl; int l=min(B.query(n-i+1,n-j+1),L); int r=min(A.query(i,j),L); // cout<<l<<" "<<r<<endl; int tmp=l+r-1; if(tmp>=L){ ans+=tmp-L+1; } } // cout<<" ans "<<ans<<endl; } printf("%lld",ans); return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2018/12/22 21:27:37 */