题意:
分析:
一看多串匹配直接上广义 (SAM) ,每一个节点分别维护一下三个串的 (siz) 这样答案每一个点对答案的贡献就是 长度在 (len[link[x]]) 到 (len[x]) 之间每一个长度的匹配数都会加上 (siz[a]*siz[b]*siz[c])
不过这里学到了一个小技巧,正确的在线构造的广义 (SAM) (即有两个特判的 (SAM)) 是可以基数排序得到拓扑序的,这样就不用 (DFS) 了
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
const int maxn = 6e5+5;
const long long mod = 1e9+7;
int n[3];
char ch[300005];
struct suffix_automaton
{
int lst,tot;
int trans[maxn][26],len[maxn],link[maxn],sa[maxn],cnt[maxn];
long long ans[maxn],siz[maxn][3];
suffix_automaton(){tot=lst=1;}
void insert(int x,int id)
{
int tmp=lst;
if(trans[tmp][x])
{
int q=trans[tmp][x];
if(len[tmp]+1==len[q]) lst=q;
else
{
int clone=++tot;
link[clone]=link[q];
link[q]=clone;
len[clone]=len[tmp]+1;
for(int i=0;i<26;i++) trans[clone][i]=trans[q][i];
for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
lst=clone;
}
siz[lst][id]++;
return ;
}
int cur=++tot;lst=tot;siz[cur][id]++;
len[cur]=len[tmp]+1;
for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
if(!tmp)
{
link[cur]=1;
}
else
{
int q=trans[tmp][x];
if(len[q]==len[tmp]+1)
{
link[cur]=q;
}
else
{
int clone=++tot;
len[clone]=len[tmp]+1;
link[clone]=link[q];
link[q]=link[cur]=clone;
for(int i=0;i<26;i++) trans[clone][i]=trans[q][i];
for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
}
}
}
void sort()
{
for(int i=1;i<=tot;i++) cnt[len[i]]++;
for(int i=1;i<=tot;i++) cnt[i]+=cnt[i-1];
for(int i=1;i<=tot;i++) sa[cnt[len[i]]--]=i;
for(int i=tot;i>=2;i--)
{
int now=sa[i];
for(int j=0;j<3;j++) siz[link[now]][j]+=siz[now][j];
long long res=siz[now][0]*siz[now][1]*siz[now][2]%mod;
ans[len[link[now]]+1]=(ans[len[link[now]]+1]+res)%mod;
ans[len[now]+1]=(ans[len[now]+1]-res+mod)%mod;
}
for(int i=1;i<=tot;i++) ans[i]=(ans[i]+ans[i-1])%mod;
for(int i=1,j=min(n[0],min(n[1],n[2]));i<=j;i++) printf("%lld ",ans[i]);
}
}sam;
void work()
{
for(int i=0;i<3;i++)
{
scanf("%s",ch+1);n[i]=strlen(ch+1);sam.lst=1;
for(int j=1;j<=n[i];j++) sam.insert(ch[j]-'a',i);
}
sam.sort();
}
}
int main()
{
zzc::work();
return 0;
}