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 */