题目分析:
求出height以后很明显跨越最小height的一定贡献是最小height,所以对于区间找出最小height再将区间对半分。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 502000; 5 const int N = 500000; 6 7 int n; 8 char str[maxn]; 9 10 int sa[maxn],rk[maxn],X[maxn],Y[maxn]; 11 int height[maxn],h[maxn],RMQ[maxn][20],pos[maxn][20]; 12 13 int chk(int x,int k){ 14 return rk[sa[x]]==rk[sa[x-1]]&&rk[sa[x]+(1<<k)]==rk[sa[x-1]+(1<<k)]; 15 } 16 17 void getsa(){ 18 for(int i=0;i<n;i++) X[str[i]]++; 19 for(int i=1;i<=N;i++) X[i] += X[i-1]; 20 for(int i=n-1;i>=0;i--) sa[X[str[i]]--] = i; 21 for(int i = 2, num = 1;i <= n;i++) 22 rk[sa[i]] = (str[sa[i]] == str[sa[i-1]]?num:++num); 23 rk[sa[1]] = 1; 24 for(int k=1;(1<<k-1)<=n;k++){ 25 for(int i=1;i<=N;i++) X[i] = 0; 26 for(int i=n-(1<<k-1);i<n;i++) Y[i-n+(1<<k-1)+1]=i; 27 for(int i=1,j=(1<<k-1)+1;i<=n;i++) 28 if(sa[i]>=(1<<k-1))Y[j++]=sa[i]-(1<<k-1); 29 for(int i=0;i<n;i++) X[rk[i]]++; 30 for(int i=1;i<=N;i++) X[i]+=X[i-1]; 31 for(int i=n;i>=1;i--) sa[X[rk[Y[i]]]--] = Y[i]; 32 int num = 1; Y[sa[1]] = 1; 33 for(int i=2;i<=n;i++) Y[sa[i]] = (chk(i,k-1)?num:++num); 34 for(int i=0;i<n;i++) rk[i] = Y[i]; 35 if(num == n) break; 36 } 37 } 38 void getheight(){ 39 for(int i=0;i<n;i++){ 40 if(i) h[i] = max(0,h[i-1]-1); else h[i] = 0; 41 if(rk[i] == 1) continue; 42 int comp = sa[rk[i]-1]; 43 while(str[comp+h[i]] == str[i+h[i]])h[i]++; 44 } 45 for(int i=0;i<n;i++) height[rk[i]] = h[i]; 46 for(int i=1;i<=n;i++) RMQ[i][0] = height[i],pos[i][0] = i; 47 for(int k=1;(1<<k)<=n;k++){ 48 for(int i=1;i<=n;i++){ 49 if(i+(1<<k-1)>n) RMQ[i][k]=RMQ[i][k-1],pos[i][k]=pos[i][k-1]; 50 else { 51 if(RMQ[i][k-1]<RMQ[i+(1<<k-1)][k-1]) pos[i][k] = pos[i][k-1]; 52 else pos[i][k] = pos[i+(1<<k-1)][k-1]; 53 RMQ[i][k] = min(RMQ[i][k-1],RMQ[i+(1<<k-1)][k-1]); 54 } 55 } 56 } 57 } 58 int getLCP(int L,int R){ 59 if(L > R) swap(L,R); 60 if(L == R) return n-sa[L]; 61 L++; 62 int k = 0; while((1<<k+1)<=R-L+1)k++; 63 if(RMQ[L][k]<RMQ[R-(1<<k)+1][k]) return pos[L][k]; 64 else return pos[R-(1<<k)+1][k]; 65 } 66 67 long long ans = 0; 68 69 void divide(int l,int r){ 70 if(l == r) return; 71 int ps = getLCP(l,r); 72 ans -= 2ll*(ps-l)*(r-ps+1)*height[ps]; 73 divide(l,ps-1); divide(ps,r); 74 } 75 76 void work(){ 77 n = strlen(str); 78 getsa(); 79 getheight(); 80 for(int i=1;i<=n;i++) ans += 1ll*i*i-i; 81 for(int i=1;i<=n;i++) ans += 1ll*i*(n-i); 82 divide(1,n); 83 printf("%lld ",ans); 84 } 85 86 int main(){ 87 scanf("%s",str); 88 work(); 89 return 0; 90 }