首先预处理SA和height数组,由于:
lcp(i,j)=min(height[k])(i+1<=k<=j)
所以问题转化为求每段区间的最小值,
30分算法:$ O(n^2) $ 暴力(简直是对后缀数组的侮辱,人家毕竟O(n*log2(n)的复杂度)
100分算法:整体思路:对于每一个height[i],找出左右边境满足min(h[k])==h[i]。
法一:二分:以为区间最小值是单调不减的,所以可以二分在O(log2(n))复杂度内找出。区间最小值用ST表预处理。
1 while(l<r) 2 { 3 int mid=(l+r)>>1,k=search(mid,i-1); 4 if(k>=h[i]) r=mid; 5 else l=mid+1; 6 } 7 x=l; 8 l=i,r=n; 9 while(l<r) 10 { 11 int mid=(l+r+1)>>1,k=search(i+1,mid); 12 if(k>h[i]) l=mid; 13 else r=mid-1; 14 } 15 y=r; 16 ans-=(y-i+1)*(i-x+1)*h[i]*2;
法二:单调栈:顺序逆序扫一边序列,弹出不满足的并更新其答案,之后把扫到的下标塞进去,最后清空栈中元素把其边境附成1或n
1 for(int i=1;i<=n;i++) 2 { 3 while(top&&h[stack[top]]>=h[i]) r[stack[top--]]=i-1; 4 stack[++top]=i; 5 } 6 while(top) r[stack[top--]]=n; 7 for(int i=n;i>=1;i--) 8 { 9 while(top&&h[stack[top]]>h[i]) l[stack[top--]]=i+1; 10 stack[++top]=i; 11 } 12 while(top) l[stack[top--]]=1;
写在后面:单调栈和ST表真的戳到了我的痛点啊,以前学过了现在思路都忘了,以后学知识还是要领会其灵魂啊!
代码都放了(二分复杂度还是不够优秀,毕竟有个log):
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<string> 8 #include<cstring> 9 #include<map> 10 #define int long long 11 #define max(a,b) (a>b?a:b) 12 #define m(a) memset(a,0,sizeof(a)) 13 #define AA cout<<"Alita"<<endl 14 using namespace std; 15 const int N=5e5+100; 16 int top,ans,n,m,a[N],X[N],Y[N],c[N],sa[N],rk[N],h[N],st[N][35],stack[N],l[N],r[N]; 17 char s[N]; 18 void init() 19 { 20 memset(st,0x3f,sizeof(st)); 21 for(int i=1;i<=n;i++) 22 { 23 st[i][0]=h[i]; 24 } 25 for(int i=1;i<=n;i++) 26 { 27 for(int j=1;j<=30;j++) 28 { 29 if((i+(1<<j))-1>n) break; 30 st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]); 31 } 32 } 33 } 34 int search(int l,int r) 35 { 36 int k=log2(r-l+1); 37 return min(st[l][k],st[r-(1<<k)+1][k]); 38 } 39 void get_sa() 40 { 41 m=27; 42 for(int i=1;i<=m;i++) c[i]=0; 43 for(int i=1;i<=n;i++) X[i]=a[i]; 44 for(int i=1;i<=n;i++) c[X[i]]++; 45 for(int i=1;i<=m;i++) c[i]+=c[i-1]; 46 for(int i=n;i>=1;i--) sa[c[X[i]]--]=i; 47 for(int len=1,p;len<=n;len<<=1) 48 { 49 p=0; 50 for(int i=n-len+1;i<=n;i++) Y[++p]=i; 51 for(int i=1;i<=n;i++) if(sa[i]>len) Y[++p]=sa[i]-len; 52 for(int i=1;i<=m;i++) c[i]=0; 53 for(int i=1;i<=n;i++) c[X[Y[i]]]++; 54 for(int i=1;i<=m;i++) c[i]+=c[i-1]; 55 for(int i=n;i>=1;i--) sa[c[X[Y[i]]]--]=Y[i]; 56 p=1; 57 swap(X,Y); 58 X[sa[1]]=1; 59 for(int i=2;i<=n;i++) 60 { 61 X[sa[i]]=Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+len]==Y[sa[i-1]+len]?p:++p; 62 } 63 if(p==n) break; 64 m=p; 65 } 66 for(int i=1;i<=n;i++) rk[sa[i]]=i; 67 } 68 void get_h() 69 { 70 for(int i=1,k=0,j;i<=n;i++) 71 { 72 if(k) k--; 73 j=sa[rk[i]-1]; 74 while(a[i+k]==a[j+k]) k++; 75 h[rk[i]]=k; 76 } 77 } 78 signed main() 79 { 80 //freopen("1.in","r",stdin); 81 //freopen("1.out","w",stdout); 82 scanf("%s",s); 83 n=strlen(s); 84 for(int i=0;i<n;i++) a[i+1]=s[i]-'a'+1; 85 get_sa(); 86 get_h(); 87 init(); 88 for(int i=1;i<=n;i++) 89 { 90 while(top&&h[stack[top]]>=h[i]) r[stack[top--]]=i-1; 91 stack[++top]=i; 92 } 93 while(top) r[stack[top--]]=n; 94 for(int i=n;i>=1;i--) 95 { 96 while(top&&h[stack[top]]>h[i]) l[stack[top--]]=i+1; 97 stack[++top]=i; 98 } 99 while(top) l[stack[top--]]=1; 100 for(int i=1;i<=n;i++) 101 { 102 ans+=(n-i+1)*(n-1)-((r[i]-i+1)*(i-l[i]+1))*h[i]*2; 103 } 104 printf("%lld",ans); 105 return 0; 106 }
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<string> 8 #include<cstring> 9 #include<map> 10 #define int long long 11 #define max(a,b) (a>b?a:b) 12 #define m(a) memset(a,0,sizeof(a)) 13 #define AA cout<<"Alita"<<endl 14 using namespace std; 15 const int N=5e5+100; 16 int ans,n,m,a[N],X[N],Y[N],c[N],sa[N],rk[N],h[N],st[N][35]; 17 char s[N]; 18 void init() 19 { 20 memset(st,0x3f,sizeof(st)); 21 for(int i=1;i<=n;i++) 22 { 23 st[i][0]=h[i]; 24 } 25 for(int j=1;j<=20;j++) 26 { 27 for(int i=1;i+(1<<(j-1))<=n;i++) 28 { 29 st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]); 30 } 31 } 32 } 33 int search(int l,int r) 34 { 35 int k=log2(r-l+1); 36 return min(st[l][k],st[r-(1<<k)+1][k]); 37 } 38 void get_sa() 39 { 40 m=27; 41 for(int i=1;i<=m;i++) c[i]=0; 42 for(int i=1;i<=n;i++) X[i]=a[i]; 43 for(int i=1;i<=n;i++) c[X[i]]++; 44 for(int i=1;i<=m;i++) c[i]+=c[i-1]; 45 for(int i=n;i>=1;i--) sa[c[X[i]]--]=i; 46 for(int len=1,p;len<=n;len<<=1) 47 { 48 p=0; 49 for(int i=n-len+1;i<=n;i++) Y[++p]=i; 50 for(int i=1;i<=n;i++) if(sa[i]>len) Y[++p]=sa[i]-len; 51 for(int i=1;i<=m;i++) c[i]=0; 52 for(int i=1;i<=n;i++) c[X[Y[i]]]++; 53 for(int i=1;i<=m;i++) c[i]+=c[i-1]; 54 for(int i=n;i>=1;i--) sa[c[X[Y[i]]]--]=Y[i]; 55 p=1; 56 swap(X,Y); 57 X[sa[1]]=1; 58 for(int i=2;i<=n;i++) 59 { 60 X[sa[i]]=Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+len]==Y[sa[i-1]+len]?p:++p; 61 } 62 if(p==n) break; 63 m=p; 64 } 65 for(int i=1;i<=n;i++) rk[sa[i]]=i; 66 } 67 void get_h() 68 { 69 for(int i=1,k=0,j;i<=n;i++) 70 { 71 if(k) k--; 72 j=sa[rk[i]-1]; 73 while(a[i+k]==a[j+k]) k++; 74 h[rk[i]]=k; 75 } 76 } 77 signed main() 78 { 79 //freopen("1.in","r",stdin); 80 //freopen("1.out","w",stdout); 81 scanf("%s",s); 82 n=strlen(s); 83 for(int i=0;i<n;i++) a[i+1]=s[i]-'a'+1; 84 get_sa(); 85 get_h(); 86 init(); 87 ans=(n+1)*n*(n-1)/2; 88 for(int i=2,l,r,x,y;i<=n;i++) 89 { 90 if(!h[i]) continue; 91 l=2,r=i; 92 while(l<r) 93 { 94 int mid=(l+r)>>1; 95 if(search(mid,i-1)>=h[i]) r=mid; 96 else l=mid+1; 97 } 98 x=l; 99 l=i,r=n; 100 while(l<r) 101 { 102 int mid=(l+r+1)>>1; 103 if(search(i+1,mid)>h[i]) l=mid; 104 else r=mid-1; 105 } 106 y=l; 107 ans-=(i-x+1)*(y-i+1)*h[i]*2; 108 } 109 printf("%lld",ans); 110 return 0; 111 }