bzoj 3238: [Ahoi2013]差异
一看字符串 最长公共前缀,用后缀数组+单调栈搞搞就行啦。一定要注意long long 啊
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #define M 2000009 10 #define EPS 1e-10 11 #define MO 19650827 12 #define ll long long 13 using namespace std; 14 ll read() 15 { 16 char ch=getchar(); 17 ll x=0,f=1; 18 for(;ch<'0'||ch>'9';ch=getchar()) 19 if(ch=='-') 20 f=-1; 21 for(;ch>='0'&&ch<='9';ch=getchar()) 22 x=x*10+ch-'0'; 23 return x*f; 24 } 25 char ch[M]; 26 int K,sa[2][M],rk[2][M],v[M],a[M],p=1,q,n,H[M],t; 27 ll ans,b[M],c[M]; 28 void work(int sa[M],int rk[M],int SA[M],int RK[M]) 29 { 30 for(int i=1;i<=n;i++) 31 v[rk[sa[i]]]=i; 32 for(int i=n;i;i--) 33 if(sa[i]>K) 34 SA[v[rk[sa[i]-K]]--]=sa[i]-K; 35 for(int i=n-K+1;i<=n;i++) 36 SA[v[rk[i]]--]=i; 37 for(int i=1;i<=n;i++) 38 RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+K]!=rk[SA[i-1]+K]); 39 } 40 int main() 41 { 42 scanf("%s",ch+1); 43 n=strlen(ch+1); 44 for(int i=1;i<=n;i++) 45 a[i]=ch[i]-'a'+1; 46 for(int i=1;i<=n;i++) 47 v[a[i]]++; 48 for(int i=1;i<=26;i++) 49 v[i]+=v[i-1]; 50 for(int i=1;i<=n;i++) 51 sa[p][v[a[i]]--]=i; 52 for(int i=1;i<=n;i++) 53 rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]); 54 K=1; 55 for(;K<n;) 56 { 57 work(sa[p],rk[p],sa[q],rk[q]); 58 swap(p,q); 59 K<<=1; 60 } 61 K=0; 62 for(int i=1;i<=n;i++) 63 if(rk[p][i]==1) 64 H[i]=0; 65 else 66 { 67 int j=sa[p][rk[p][i]-1]; 68 for(;a[i+K]==a[j+K];K++); 69 H[i]=K; 70 if(K) 71 K--; 72 } 73 ll su=0; 74 for(int i=n-1;i;i--) 75 { 76 ll a1=H[sa[p][i+1]],s=1; 77 for(;b[t]>a1;) 78 { 79 s+=c[t]; 80 su-=b[t]*c[t]; 81 t--; 82 } 83 su+=a1*s; 84 if(b[t]==a1) 85 c[t]+=s; 86 else 87 { 88 b[++t]=a1; 89 c[t]=s; 90 } 91 ans+=su; 92 } 93 printf("%lld\n",(ll)(n-1)*n*(n+1)/2-2*ans); 94 return 0; 95 } 96