正题
P4248
题目大意
设TiT_iTi为第i个字符开始的后缀,求:
∑i=1n∑j=i+1nlen(Ti)+len(Tj)−2×lcp(Ti,Tj)\sum_{i=1}^n \sum_{j=i+1}^n len(T_i)+len(T_j)-2\times lcp(T_i,T_j)i=1∑nj=i+1∑nlen(Ti)+len(Tj)−2×lcp(Ti,Tj)
解题思路
用SAM建立parent树
parent树中一个点x的不同儿子会产生贡献∑y∈sonx(leny−lenx)×szy\sum_{y\in son_x}(len_y-len_x)\times sz_y∑y∈sonx(leny−lenx)×szy(当前子串会重合,而后面部分不重合)
那么可以在x和son之间建立长为leny−lenxlen_y-len_xleny−lenx的边,然后跑dfs
code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 500100
using namespace std;
ll n,w,lst,tot,ans,h[N<<1],sz[N<<1],fa[N<<1],len[N<<1],ch[N<<1][30];
char s[N];
struct rec
{ll to,nx,l;
}e[N<<1];
void addl(ll x,ll y,ll z)
{e[++tot].to=y;e[tot].l=z;e[tot].nx=h[x];h[x]=tot;return;
}
void add(ll c)
{ll p=lst,np=lst=++w;sz[np]=1;len[np]=len[p]+1;while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];if(!p)fa[np]=1;else{ll q=ch[p][c];if(len[q]==len[p]+1)fa[np]=q;else{ll nq=++w;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[q]));fa[nq]=fa[q];fa[np]=fa[q]=nq;while(p&&ch[p][c]==q)ch[p][c]=nq,p=fa[p];}}return;
}
void dfs(ll x)
{for(ll i=h[x];i;i=e[i].nx){ll y=e[i].to;dfs(y);ans+=(n-sz[y])*sz[y]*e[i].l;sz[x]+=sz[y];}return;
}
int main()
{scanf("%s",s+1);n=strlen(s+1);lst=w=1;for(ll i=1;i<=n;++i)add(s[i]-'a');for(ll i=2;i<=w;++i)addl(fa[i],i,len[i]-len[fa[i]]);dfs(1);printf("%lld",ans);return 0;
}