1. 程式人生 > >BZOJ 2119 股市的預測 (字尾陣列+RMQ)

BZOJ 2119 股市的預測 (字尾陣列+RMQ)

題目大意:求一個字串中形如$ABA$的串的數量,其中$B$的長度是給定的

有點像[NOI2016]優秀的拆分這道題

先對序列打差分,然後離散,再正反跑$SA$,跑出$st$表

進入正題

$ABA$串有一個神奇的性質

令$A$串長度是$x$

如果我們選取了一個位置$i$,再選取一個位置$i+x+m$

用預處理的$st$表,求出經過它們的,最長的相同子串的起始位置$s$和結束位置$e$

合法的$ABA$串似乎在$[s,e]$之間滑動

有了這個性質,我們再外層列舉長度$x$,在序列中找出一些相隔為$x$的關鍵點,求滑動視窗的左$A$串部分,每次當且僅當覆蓋一個關鍵點時,能覆蓋的最長距離總和

總時間$O(n(lnn+logn))$

別像我一樣把RMQ打錯還調了20min

  1 #include <map>
  2 #include <cmath>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define N1 50500
  7 #define ll long long
  8 #define uint unsigned int
  9 #define rint register int 
 10
#define il inline 11 #define it map<int,int>::iterator 12 #define inf 0x3f3f3f3f 13 using namespace std; 14 15 int gint() 16 { 17 int ret=0,fh=1;char c=getchar(); 18 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 19 while(c>='0'&&c<='9'){ret=ret*10
+c-'0';c=getchar();} 20 return ret*fh; 21 } 22 23 int n,m,len,nn; 24 int lg[N1]; 25 struct SA{ 26 int a[N1],tr[N1],rk[N1],hs[N1],sa[N1],h[N1],f[N1][17]; 27 int check(int i,int j,int k){ 28 if(i+k>len||j+k>len) return 0; 29 return (rk[i]==rk[j]&&rk[i+k]==rk[j+k])?1:0; 30 } 31 void Pre() 32 { 33 rint i,cnt=0; 34 for(i=1;i<=len;i++) hs[a[i]]++; 35 for(i=1;i<=nn;i++) if(hs[i]) tr[i]=++cnt; 36 for(i=1;i<=nn;i++) hs[i]+=hs[i-1]; 37 for(i=1;i<=len;i++) rk[i]=tr[a[i]],sa[hs[a[i]]--]=i; 38 for(int k=1;cnt<len;k<<=1) 39 { 40 for(i=1;i<=cnt;i++) hs[i]=0; 41 for(i=1;i<=len;i++) hs[rk[i]]++; 42 for(i=1;i<=cnt;i++) hs[i]+=hs[i-1]; 43 for(i=len;i>=1;i--) if(sa[i]>k) tr[sa[i]-k]=hs[rk[sa[i]-k]]--; 44 for(i=1;i<=k;i++) tr[len-i+1]=hs[rk[len-i+1]]--; 45 for(i=1;i<=len;i++) sa[tr[i]]=i; 46 for(i=1,cnt=0;i<=len;i++) tr[sa[i]]=check(sa[i],sa[i-1],k)?cnt:++cnt; 47 for(i=1;i<=len;i++) rk[i]=tr[i]; 48 } 49 for(i=1;i<=len;i++){ 50 if(rk[i]==1) continue; 51 for(int j=max(1,h[rk[i-1]]-1);;j++) 52 if(a[i+j-1]==a[sa[rk[i]-1]+j-1]) h[rk[i]]=j; 53 else break; 54 } 55 for(i=2;i<=len;i++) f[i][0]=h[i]; 56 for(int j=1;j<=lg[len];j++) 57 for(i=2;i+(1<<j)-1<=len;i++) 58 f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]); 59 } 60 int query(int i,int j){ 61 int x=rk[i],y=rk[j]; 62 if(x>y) swap(x,y);x++;int _L=y-x+1; 63 if(_L<0) return 0; 64 return min(f[x][lg[_L]],f[y-(1<<lg[_L])+1][lg[_L]]); 65 } 66 }p,s; 67 int a[N1],A[N1],tmp[N1]; 68 int lower(int l,int r,int *t,int val){ 69 int ans=-inf,id,mid; 70 while(l<=r){ 71 mid=(l+r)>>1; 72 if(t[mid]<=val&&t[mid]>ans) ans=t[mid],id=mid,l=mid+1; 73 else r=mid-1; 74 }return id; 75 } 76 77 int main() 78 { 79 scanf("%d%d",&n,&m); 80 rint i,j;len=n-1; 81 for(lg[1]=0,i=2;i<=n;i++) lg[i]=lg[i>>1]+1; 82 A[1]=gint(); 83 for(i=2;i<=n;i++) A[i]=gint(),a[i-1]=tmp[i-1]=A[i]-A[i-1]; 84 sort(tmp+1,tmp+len+1); 85 nn=unique(tmp+1,tmp+len+1)-(tmp+1); 86 for(i=1;i<=len;i++) a[i]=lower(1,nn,tmp,a[i]); 87 for(i=1;i<=len;i++) s.a[i]=a[len-i+1],p.a[i]=a[i]; 88 p.Pre(),s.Pre(); 89 int lx,rx;ll ans=0; 90 for(j=1;j<=len;j++) 91 { 92 for(i=1;i+j+m<=len;i+=j) 93 { 94 lx=min(s.query(len-i+1,len-(i+j+m)+1),j); 95 rx=min(p.query(i+1,i+1+j+m),j-1); 96 ans+=max(0,lx+rx-j+1); 97 } 98 } 99 printf("%lld\n",ans); 100 return 0; 101 } 102 /* 103 2 2 2 3 2 1 2 2 2 3 2 104 105 1 2 2 2 3 2 106 2 107 2 1 2 2 2 3 2 108 2 2 2 3 2 109 2 2 2 3 2 1 2 2 2 3 2 110 2 2 3 2 111 2 2 3 2 1 2 2 2 3 2 112 2 3 2 113 2 3 2 1 2 2 2 3 2 114 3 2 115 3 2 1 2 2 2 3 2 116 117 2 3 2 2 2 1 2 3 2 2 2 118 119 1 2 3 2 2 2 120 2 121 2 1 2 3 2 2 2 122 2 2 123 2 2 1 2 3 2 2 2 124 2 2 2 125 2 2 2 1 2 3 2 2 2 126 2 3 2 2 2 127 2 3 2 2 2 1 2 3 2 2 2 128 3 2 2 2 129 3 2 2 2 1 2 3 2 2 2 130 */