建出广义SAM,通过parent树对每个节点求出其是否仅被一个子串包含及被哪个包含。
写了无数个sam板子题一点意思都没啊
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 200010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,son[N][26],fail[N],len[N],f[N],q[N],tmp[N],cnt=1,last; ll ans[N]; char s[N]; int ins(int c,int p,int i) { int u; if (son[p][c]) { int q=son[p][c]; if (len[p]+1==len[q]) u=q; else { int y=++cnt; len[y]=len[p]+1; memcpy(son[y],son[q],sizeof(son[q])); fail[y]=fail[q],fail[q]=y; while (son[p][c]==q) son[p][c]=y,p=fail[p]; u=y; } } else { int x=++cnt;len[x]=len[p]+1; while (!son[p][c]&&p) son[p][c]=x,p=fail[p]; if (!p) fail[x]=1; else { int q=son[p][c]; if (len[p]+1==len[q]) fail[x]=q; else { int y=++cnt; len[y]=len[p]+1; memcpy(son[y],son[q],sizeof(son[q])); fail[y]=fail[q],fail[x]=fail[q]=y; while (son[p][c]==q) son[p][c]=y,p=fail[p]; } } u=x; } if (f[u]==-1) f[u]=i;else if (f[u]!=i) f[u]=0; return u; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read();memset(f,255,sizeof(f)); for (int i=1;i<=n;i++) { scanf("%s",s+1); m=strlen(s+1);last=1; for (int j=1;j<=m;j++) last=ins(s[j]-'a',last,i); } for (int i=1;i<=cnt;i++) tmp[len[i]]++; for (int i=1;i<=cnt;i++) tmp[i]+=tmp[i-1]; for (int i=1;i<=cnt;i++) q[tmp[len[i]]--]=i; for (int i=cnt;i>=1;i--) { int x=q[i]; if (f[x]>0) ans[f[x]]+=len[x]-len[fail[x]]; if (f[fail[x]]==-1) f[fail[x]]=f[x]; else if (f[fail[x]]!=f[x]) f[fail[x]]=0; } for (int i=1;i<=n;i++) printf("%lld ",ans[i]); return 0; //NOTICE LONG LONG!!!!! }