CF452E Three strings 廣義SAM
阿新 • • 發佈:2021-01-02
題意:
分析:
一看多串匹配直接上廣義 \(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; }