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

 

posted @ 2018-12-09 15:07  guapisolo  阅读(188)  评论(0编辑  收藏  举报