[AHOI2013]差异
题目描述
给定一个长度为 $n$ 的字符串 $S$ ,令 $T_i$ 表示它从第 $i$ 个字符开始的后缀。求
$\displaystyle \sum_{1\leqslant i<j\leqslant n}\text{len}(T_i)+\text{len}(T_j)-2\times\text{lcp}(T_i,T_j)$
其中,$\text{len}(a)$ 表示字符串 $a$ 的长度,$\text{lcp}(a,b)$ 表示字符串 $a$ 和字符串 $b$ 的最长公共前缀。
输入输出格式
输入格式:一行,一个字符串 $S$ 。
输出格式:一行,一个整数,表示所求值。
输入输出样例
说明
对于 100% 的数据,保证 $2\leqslant n\leqslant 500000$ ,且均为小写字母。
先用后缀数组求出height数组(h数组)
那么两个点i,j的LCP就是$min{h[k] | i+1<=k<=j}$
考虑每个h[i]的贡献
假设L[i]表示L[i]~i-1的h值都大于等于h[i]
而R[i]表示i+1~R[i]的h值大于h[i](之所以不是大于等于是为了避免相同的h带来重复答案)
$ans-=2*lcp(T_i,T_j)$
$ans-=2*(i-L[i]+1)*(R[i]-i+1)*h[i]$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 typedef long long lol; 8 int n,m,c[600001]; 9 int x[600001],y[600001],SA[600001],s[600001],rank[600001],st[600001],top; 10 lol L[600001],R[600001]; 11 lol h[600001],ans,sum; 12 char ch[600001]; 13 void radix_sort() 14 {int i; 15 for (i=0;i<m;i++) 16 c[i]=0; 17 for (i=0;i<n;i++) 18 c[x[y[i]]]++; 19 for (i=1;i<m;i++) 20 c[i]+=c[i-1]; 21 for (i=n-1;i>=0;i--) 22 SA[--c[x[y[i]]]]=y[i]; 23 } 24 void build() 25 {int i,j,k,p; 26 for (i=0;i<n;i++) 27 y[i]=i,x[i]=s[i]; 28 m=500000; 29 radix_sort(); 30 for (k=1;k<=n;k*=2) 31 { 32 p=0; 33 for (i=n-k;i<n;i++) 34 y[p++]=i; 35 for (i=0;i<n;i++) 36 if (SA[i]>=k) y[p++]=SA[i]-k; 37 radix_sort(); 38 p=1;swap(x,y); 39 x[SA[0]]=0; 40 for (i=1;i<n;i++) 41 x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&((SA[i]+k<n?y[SA[i]+k]:-1)==(SA[i-1]+k<n?y[SA[i-1]+k]:-1)))?p-1:p++; 42 if (p>n) break; 43 m=p; 44 } 45 for (i=0;i<n;i++) 46 rank[SA[i]]=i; 47 int len=0; 48 for (i=0;i<n;i++) 49 if(rank[i]>0) 50 { 51 if (len) len--; 52 j=SA[rank[i]-1]; 53 while (i+len<n&&j+len<n&&(s[i+len]==s[j+len])) len++; 54 h[rank[i]]=len; 55 } 56 } 57 int main() 58 {int i,j; 59 cin>>ch; 60 n=strlen(ch); 61 for (i=0;i<n;i++) 62 { 63 s[i]=ch[i]-'a'+1; 64 } 65 build(); 66 for (i=0;i<n;i++) 67 { 68 while (top&&h[i]<=h[st[top]]) top--; 69 if (top==0) L[i]=0; 70 else L[i]=st[top]+1; 71 st[++top]=i; 72 } 73 top=0; 74 for (i=n-1;i>=0;i--) 75 { 76 while (top&&h[i]<h[st[top]]) top--; 77 if (top==0) R[i]=n-1; 78 else R[i]=st[top]-1; 79 st[++top]=i; 80 } 81 for (i=1;i<=n;i++) 82 ans+=(lol)i*(lol)(n-1); 83 for (i=0;i<n;i++) 84 { 85 ans-=2ll*((lol)i-(lol)L[i]+1ll)*((lol)R[i]-(lol)i+1ll)*(lol)h[i]; 86 } 87 printf("%lld\n",ans); 88 }