Description
Input
一行,一个字符串S
Output
一行,一个整数,表示所求值
Sample Input
cacao
Sample Output
54
HINT
2<=N<=500000,S由小写英文字母组成
前面的直接加就可以了。
后面要减去的lcp就是品酒大会的第一问,排完序后用并查集搞一下就可以了。
记得开LL。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<algorithm> 7 #include<map> 8 #include<complex> 9 #include<queue> 10 #include<stack> 11 #include<cmath> 12 #include<set> 13 #include<vector> 14 #define maxn 500010 15 #define LL long long 16 using namespace std; 17 char s[maxn]; 18 int n,k,sa[maxn],tmp[maxn],rk[maxn],fa[maxn]; 19 LL size[maxn]; 20 struct data{ 21 LL k; 22 int id; 23 }lcp[maxn]; 24 bool cmp(int i,int j){ 25 if(rk[i]!=rk[j]) return rk[i]<rk[j]; 26 else{ 27 int ri=i+k<=n?rk[i+k]:-1,rj=j+k<=n?rk[j+k]:-1; 28 return ri<rj; 29 } 30 } 31 void get_sa(){ 32 for(int i=0;i<=n;i++) 33 sa[i]=i,rk[i]=i<n?s[i]:-1; 34 for(k=1;k<=n;k*=2){ 35 sort(sa,sa+n+1,cmp); 36 tmp[sa[0]]=0; 37 for(int i=1;i<=n;i++) 38 tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0); 39 for(int i=0;i<=n;i++) rk[i]=tmp[i]; 40 } 41 } 42 void get_lcp(){ 43 for(int i=0;i<=n;i++) rk[sa[i]]=i; 44 int h=0; 45 lcp[0].k=0; 46 for(int i=0;i<n;i++){ 47 int j=sa[rk[i]-1]; 48 if(h>0) h--; 49 for(;j+h<n && i+h<n;h++) 50 if(s[j+h]!=s[i+h]) break; 51 lcp[rk[i]-1].k=h; 52 } 53 } 54 bool CMP(const data &a,const data &b){ 55 return a.k>b.k; 56 } 57 int find(int x){ 58 if(fa[x]!=x) fa[x]=find(fa[x]); 59 return fa[x]; 60 } 61 int main(){ 62 scanf("%s",s); 63 n=strlen(s); 64 LL ans=0; 65 for(int i=0;i<=n;i++) fa[i]=i,size[i]=1; 66 get_sa(); 67 get_lcp(); 68 for(int i=1;i<n;i++) lcp[i].id=i; 69 sort(lcp+1,lcp+n,CMP); 70 for(int i=1;i<n;i++){ 71 int u=find(lcp[i].id),v=find(lcp[i].id+1); 72 ans+=lcp[i].k*size[u]*size[v]; 73 fa[v]=u; 74 size[u]+=size[v]; 75 } 76 LL ans1=0; 77 for(LL i=n;i>=1;i--)ans1+=i*(i-1)+i*(n-i); 78 printf("%lld",ans1-2*ans); 79 return 0; 80 }