[BZOJ3238][AHOI2013]差异(后缀数组)

求和式的前两项可以直接算,问题是对于每对i,j计算LCP。

一个比较显然的性质是,LCP(i,j)是h[rk[i]+1~rk[j]]中的最小值。

从h的每个元素角度考虑,就是对每个h计算有多少对i,j以它为最小值。

在h中使用单调栈统计左右比它小的第一个元素,相乘得到结果。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=1000010,inf=1000000000;
 9 ll ans;
10 char s[N];
11 int n,top,x[N],y[N],c[N],sa[N],h[N],rk[N],l[N],r[N],stk[N];
12 int Cmp(int a,int b,int l){ return a+l<=n && b+l<=n && y[a]==y[b] && y[a+l]==y[b+l]; }
13 
14 void build_sa(int m){
15     memset(y,0,sizeof(y));
16     rep(i,0,m) c[i]=0;
17     rep(i,1,n) c[x[i]=s[i]-'a'+1]++;
18     rep(i,1,m) c[i]+=c[i-1];
19     for (int i=n; i; i--) sa[c[x[i]]--]=i;
20     for (int k=1,p=0; p<n; k<<=1,m=p){
21          p=0;
22          rep(i,n-k+1,n) y[++p]=i;
23          rep(i,1,n) if (sa[i]>k) y[++p]=sa[i]-k;
24          rep(i,0,m) c[i]=0;
25          rep(i,1,n) c[x[y[i]]]++;
26          rep(i,1,m) c[i]+=c[i-1];
27          for (int i=n; i; i--) sa[c[x[y[i]]]--]=y[i];
28          rep(i,1,n) y[i]=x[i]; p=1; x[sa[1]]=1;
29          rep(i,2,n) x[sa[i]]=Cmp(sa[i-1],sa[i],k) ? p : ++p;
30     }
31 }
32 
33 void get(){
34     int k=0;
35     rep(i,1,n) rk[sa[i]]=i;
36     rep(i,1,n){
37          for (int j=sa[rk[i]-1]; i+k<=n && j+k<=n && s[i+k]==s[j+k]; k++);
38          h[rk[i]]=k; if (k) k--;
39     }
40 }
41 
42 void solve(){
43     rep(i,1,n) ans+=1ll*i*(n-1);
44     h[0]=-inf;
45     rep(i,1,n){
46         while (h[i]<=h[stk[top]]) top--;
47         if (!stk[top]) l[i]=1; else l[i]=stk[top]+1;
48         stk[++top]=i;
49     }
50     h[n+1]=-inf; top=0; stk[0]=n+1;
51     for (int i=n; i; i--){
52         while (h[i]<h[stk[top]]) top--;
53         if (stk[top]==n+1) r[i]=n; else r[i]=stk[top]-1;
54         stk[++top]=i;
55     }
56     rep(i,1,n) ans-=2ll*(i-l[i]+1)*(r[i]-i+1)*h[i];
57 }
58 
59 int main(){
60     freopen("bzoj3238.in","r",stdin);
61     freopen("bzoj3238.out","w",stdout);
62     scanf("%s",s+1); n=strlen(s+1);
63     build_sa(300); get(); solve(); printf("%lld\n",ans);
64     return 0;
65 }

 

posted @ 2018-08-08 10:32  HocRiser  阅读(168)  评论(0编辑  收藏  举报