[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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11249773.html