P4081 [USACO17DEC]Standing Out from the Herd P 廣義SAM
阿新 • • 發佈:2020-12-27
題意:
分析:
一看見本質不同的字串 \(\to\) \(SAM\)
再一看,字串集合 \(\to\) 廣義 \(SAM\)
所以這個題的做法就是,建一顆廣義 \(SAM\) , \(dfs\) 這個 \(SAM\) ,把只出現了一次的點標起來,它的貢獻就是 \(len[x]-len[link[x]]\) ,注意沒有被標過的點,他屬於它的兒子所在的集合
tip:
廣義SAM好像不能像普通的SAM一樣,通過基數排序得到它的拓撲序
程式碼:
#include<bits/stdc++.h> #define pii pair<int,int> #define mk(x,y) make_pair(x,y) #define lc rt<<1 #define rc rt<<1|1 #define pb push_back #define fir first #define sec second using namespace std; namespace zzc { inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } const int maxn = 2e5+5; int n; long long ans[maxn]; char ch[maxn]; vector<int> tmp[maxn]; namespace suffix_automaton//¹ãÒåSAMÔÚÏß¹¹Ôì°æ { int cnt,lst; int link[maxn],len[maxn],trans[maxn][26],flag[maxn]; void insert(int x,int p) { if(trans[lst][x]) { int tmp=lst,q=trans[tmp][x]; if(len[tmp]+1==len[q]) { flag[q]=-1; lst=q; } else { int clone=++cnt; len[clone]=len[tmp]+1; link[clone]=link[q]; link[q]=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; lst=clone;flag[clone]=p; } return ; } int cur=++cnt,tmp=lst;lst=cnt; len[cur]=len[tmp]+1; if(!flag[cur]) flag[cur]=p; else flag[cur]=-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[tmp]+1==len[q]) { link[cur]=q; } else { int clone=++cnt; len[clone]=len[tmp]+1; link[clone]=link[q]; link[cur]=link[q]=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; } } } } using namespace suffix_automaton; void dfs(int u) { for(auto v:tmp[u]) { dfs(v); if(!flag[u]) flag[u]=flag[v]; else if(flag[u]!=flag[v]) flag[u]=-1; } if(flag[u]!=-1) ans[flag[u]]+=len[u]-len[link[u]]; } void work() { n=read();cnt=1; for(int i=1;i<=n;i++) { scanf("%s",ch+1); int len=strlen(ch+1); lst=1; for(int j=1;j<=len;j++) insert(ch[j]-'a',i); } for(int i=1;i<=cnt;i++) tmp[link[i]].push_back(i); dfs(1); for(int i=1;i<=n;i++) printf("%lld\n",ans[i]); } } int main() { zzc::work(); return 0; }