[bzoj3238]差异
对于前两个sigma,可以直接处理,相当于求$\sum\limits_{1\leq i<j\leq n}lcp(i,j)$ 。
倒序字符串后的parent树(后缀树),lcp(i,j)其实就是i这个前缀和j这个前缀parent树上的lca,则对于任意一个节点,考虑其为lca的方案,就是任意两个儿子中有多少个前缀的乘积,树形dp即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 int V,last,a[N<<1],sz[N<<1],sum[N<<1],id[N<<1],len[N<<1],fa[N<<1],ch[N<<1][31]; 5 long long ans; 6 char s[N]; 7 void add(int c){ 8 int p=last,np=last=++V; 9 len[np]=len[p]+1; 10 sum[np]=sz[np]=1; 11 for(;(p)&&(!ch[p][c]);p=fa[p])ch[p][c]=V; 12 if (!p)fa[np]=1; 13 else{ 14 int q=ch[p][c]; 15 if (len[q]==len[p]+1)fa[np]=q; 16 else{ 17 int nq=++V; 18 len[nq]=len[p]+1; 19 memcpy(ch[nq],ch[q],sizeof(ch[q])); 20 fa[nq]=fa[q]; 21 fa[q]=fa[np]=nq; 22 for(;(p)&&(ch[p][c]==q);p=fa[p])ch[p][c]=nq; 23 } 24 } 25 } 26 int main(){ 27 scanf("%s",s); 28 int l=strlen(s); 29 V=last=1; 30 for(int i=l-1;i>=0;i--)add(s[i]-'a'); 31 for(int i=1;i<=V;i++)a[len[i]]++; 32 for(int i=0;s[i];i++)a[i+1]+=a[i]; 33 for(int i=1;i<=V;i++)id[a[len[i]]--]=i; 34 for(int i=V;i;i--)sz[fa[id[i]]]+=sz[id[i]]; 35 for(int i=V;i;i--){ 36 ans+=1LL*sum[fa[id[i]]]*sz[id[i]]*len[fa[id[i]]]; 37 sum[fa[id[i]]]+=sz[id[i]]; 38 } 39 printf("%lld",1LL*l*(l-1)*(l+1)/2-2*ans); 40 }