對多串創建SAM的一種方法是加分隔符。因而加完分隔符建出SAM。ios
考慮統計出每一個節點被多少個串包含。讓每一個串各自在SAM上跑,跑到一個節點就標記(顯然必定會徹底匹配該節點,由於是對包含其的串建的SAM)並暴跳fail,遇到已經被該串標記過的點就中止。spa
這樣暴力的複雜度容易感性證實是O(Lsqrt(L))(L即全部串總長度),由於暴力一個串的過程當中,SAM每一個點至多被標記一次,每一步跳fail的次數也顯然不會超過該串長度,因而對該串的複雜度是min(L,|S|2)(S即該串長度),總的最劣複雜度大約就是sqrt(L)個長度爲sqrt(L)的串時取得,且常數極小。固然也可使用樹剖實現,不用分析複雜度就能知道是O(Llog2L)。blog
而後遞推求出每一個點被通過時的具體貢獻,也即其到parent樹的根的路徑上全部出如今至少k個串中的點的len-lenfa值的和。再對每一個串各自跑一遍累加所通過點的貢獻便可。get
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; #define ll long long #define N 400010 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,k,s[N],l[N],r[N],son[N][27],q[N],tot[N],fail[N],len[N],f[N],g[N],cnt=1,last=1; char qwq[N]; bool flag[N]; vector<int> a; void ins(int c) { int x=++cnt,p=last;last=x;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[q]==len[p]+1) 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]; } } } int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),k=read(); for (int i=1;i<=n;i++) { scanf("%s",qwq+1); int _=strlen(qwq+1); l[i]=m+1,r[i]=m+_; for (int j=1;j<=_;j++) s[++m]=qwq[j]-'a'; s[++m]=26; } for (int i=1;i<=m;i++) ins(s[i]); for (int i=1;i<=n;i++) { int k=1; for (int j=l[i];j<=r[i];j++) { while (!son[k][s[j]]) k=fail[k]; if (!k) k=1; else { k=son[k][s[j]]; for (int x=k;!flag[x];x=fail[x]) flag[x]=1,f[x]++,a.push_back(x); } } for (int j:a) flag[j]=0;a.clear(); } for (int i=1;i<=cnt;i++) tot[len[i]]++; for (int i=1;i<=m;i++) tot[i]+=tot[i-1]; for (int i=1;i<=cnt;i++) q[tot[len[i]]--]=i; for (int i=1;i<=cnt;i++) { int x=q[i]; g[x]=g[fail[x]]; if (f[x]>=k) g[x]+=len[x]-len[fail[x]]; } for (int i=1;i<=n;i++) { ll ans=0;int k=1; for (int j=l[i];j<=r[i];j++) { while (!son[k][s[j]]) k=fail[k]; if (!k) k=1; else k=son[k][s[j]],ans+=g[k]; } printf(LL,ans); } return 0; }