Description
给定$n$个字符串,询问每个字符串有多少子串(不包括空串)是所有$n$个字符串中至少$k$个字符串的子串?
Solution
建广义后缀自动机,对于每一个字符串给它的所有子串节点计数,在parent树上从根向下合并,对于每个字符串,答案为其所有前缀的权值和,时间复杂度$O(n sqrt n)$(由均值不等式可证)
数据:链接:https://pan.baidu.com/s/17yytL_cLsivciz4Mpos3GA 提取码:se5o

#pragma GCC optimize(2) #include<iostream> #include<cstring> #include<string> #include<cstdio> using namespace std; int n,k,tot=1,las=1,buc[200005],topo[200005]; long long dp[200005]; char str[200005]; string s[200005]; struct SAM { int ch[26],len,fa,cnt,col; }sam[200005]; inline int read() { int w=0,f=1; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return w*f; } void insert(int c) { int p=las,np=las=++tot; sam[np].len=sam[p].len+1; for(;p&&!sam[p].ch[c];p=sam[p].fa) { sam[p].ch[c]=np; } if(!p) { sam[np].fa=1; } else { int q=sam[p].ch[c]; if(sam[q].len==sam[p].len+1) { sam[np].fa=q; } else { int nq=++tot; sam[nq]=sam[q]; sam[nq].len=sam[p].len+1; sam[q].fa=sam[np].fa=nq; for(;p&&sam[p].ch[c]==q;p=sam[p].fa) { sam[p].ch[c]=nq; } } } } int main() { n=read(); k=read(); for(int i=1;i<=n;i++) { scanf("%s",str); s[i]=string(str); las=1; for(int j=0;str[j];j++) { insert(str[j]-'a'); } } for(int i=1;i<=n;i++) { int p=1; for(int j=0;s[i][j];j++) { p=sam[p].ch[s[i][j]-'a']; int temp=p; while(temp) { if(sam[temp].col!=i) { sam[temp].col=i; ++sam[temp].cnt; } else { break; } temp=sam[temp].fa; } } } for(int i=1;i<=tot;i++) { ++buc[sam[i].len]; } for(int i=1;i<=tot;i++) { buc[i]+=buc[i-1]; } for(int i=1;i<=tot;i++) { topo[buc[sam[i].len]--]=i; } sam[1].cnt=0; for(int i=1;i<=tot;i++) { dp[topo[i]]+=dp[sam[topo[i]].fa]; if(sam[topo[i]].cnt>=k) { dp[topo[i]]+=sam[topo[i]].len-sam[sam[topo[i]].fa].len; } } for(int i=1;i<=n;i++) { long long ans=0,p=1; for(int j=0;s[i][j];j++) { p=sam[p].ch[s[i][j]-'a']; ans+=dp[p]; } printf("%lld ",ans); } return 0; }