【题目】
lydsy
CF
给定
n
n
n个字符串,问每个字符串有多少个非空子串是所有
n
n
n个字符串中至少
k
k
k个的子串。
∑
∣
S
∣
≤
1
0
5
\sum |S|\leq 10^5
∑∣S∣≤105
【解题思路】
广义
SAM
\text{SAM}
SAM板子题。
每个节点维护一个
set
\text{set}
set来启发式合并可以得到该节点子串所有的颜色,于是就可以记下来有哪些节点有贡献。
再用每个串在
SAM
\text{SAM}
SAM上匹配,当匹配的当前节点颜色树小于
K
K
K就一直往
f
a
fa
fa跳,否则往下走即可。答案即为经过所有点的
m
x
mx
mx值和。
复杂度
O
(
n
log
2
n
)
O(n\log ^2 n)
O(nlog2n)
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int n,K;
char s[N];
namespace String
{
set<int>st[N];
int b[N],c[N],bl[N],sum[N];
vector<int>G[N];
struct SAM
{
int sz,las,mx[N],fa[N],ch[N][26];
SAM(){sz=las=1;}
void extend(int x)
{
int p,np,q,nq;
if(ch[las][x])
{
p=las;las=q=ch[p][x];
if(mx[q]==mx[p]+1) return;
las=nq=++sz;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=nq;
for(;p && ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
return;
}
p=las;np=las=++sz;mx[np]=mx[p]+1;
for(;p && !ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=1;
else
{
q=ch[p][x];
if(mx[q]==mx[p]+1) fa[np]=q;
else
{
nq=++sz;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;p && ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
}S;
void stmerge(int x,int y)
{
if(st[x].size()<st[y].size()) swap(st[x],st[y]);
//for(auto v:st[y]) st[x].insert(v);
for(set<int>::iterator it=st[y].begin();it!=st[y].end();++it) st[x].insert(*it);
st[y].clear();
}
void merge()
{
for(int i=1;i<=S.sz;++i) b[S.mx[i]]++;
for(int i=1;i<=S.sz;++i) b[i]+=b[i-1];
for(int i=S.sz;i;--i) c[b[S.mx[i]]--]=i;
for(int i=S.sz,x;i;--i) x=c[i],sum[x]=st[x].size(),stmerge(S.fa[x],x);
}
}
using namespace String;
namespace DreamLolita
{
int n,K;
vector<string>Q;
void solution()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);int m=strlen(s+1);S.las=1;string now="";
for(int j=1;j<=m;++j) S.extend(s[j]-'a'),st[S.las].insert(i),now+=s[j];
Q.push_back(now);
}
merge();
if(K>n){for(int i=1;i<=n;++i)putchar('0'),putchar(' ');return;}
for(int i=0;i<n;++i)
{
ll res=0;int now=1,len=Q[i].length();
for(int j=0;j<len;++j)
{
now=S.ch[now][Q[i][j]-'a'];
for(;sum[now]<K;now=S.fa[now]);
res+=S.mx[now];
}
printf("%lld ",res);
}
}
}
int main()
{
#ifdef Durant_Lee
freopen("BZOJ3473.in","r",stdin);
freopen("BZOJ3473.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}