Description
字符串是oi界常考的问题。现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中
至少k个字符串的子串(注意包括本身)。
Input
第一行两个整数n,k。 接下来n行每行一个字符串。 n,k,l<=100000
Output
输出一行n个整数,第i个整数表示第i个字符串的答案。
Sample Input
3 1
abc
a
ab
Sample Output
6 1 3
题解
怎么连SAM基本玩法都不会了呀…
先预处理出每个状态点在多少个字符串中
设mark[i]表示第i个状态最后一次被找到是在哪个字符串中 ct[i]表示这个状态出现在多少字符串中
每次插入的时候暴力跳parent
如果mark[parent]!=当前串 则把mark[parent]赋值为当前串并且ct++
每个状态点表示的本质不同的字符串有dep[i]-dep[parent[i]]个
如果这个状态点的ct>=K 则它的权值为dep[i]-dep[parent[i]] 否则为0
这样求出来的是不重复的 但是题目要求是可以重复
所以还要加上他的parent树所有祖先的权值
之后扫串更新答案
在建新节点的时候记得记得记得拷他的mark和ct…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
vector<int> hh[110000];
struct node{int x,y,next;}a[810000];int len,last[410000];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
struct SAM
{
int son[30],dep,parent;
}tr[410000];int root,cnt,LA,T;
int ct[410000],mark[410000];//这个节点是否被标记过
char ch[410000];
void add(int x)
{
int np=++cnt,p=LA;
tr[np].dep=tr[p].dep+1;
while(p&&!tr[p].son[x])tr[p].son[x]=np,p=tr[p].parent;
if(!p)tr[np].parent=root;
else
{
int q=tr[p].son[x];
if(tr[q].dep==tr[p].dep+1)tr[np].parent=q;
else
{
int nq=++cnt;
tr[nq]=tr[q];tr[nq].dep=tr[p].dep+1;ct[nq]=ct[q];mark[nq]=mark[q];
tr[q].parent=tr[np].parent=nq;
while(p&&tr[p].son[x]==q)tr[p].son[x]=nq,p=tr[p].parent;
}
}
LA=np;
while(np&&mark[np]!=T)ct[np]++,mark[np]=T,np=tr[np].parent;
}
LL f[210000];
void dfs(int x)
{
f[x]+=f[tr[x].parent];
for(int k=last[x];k;k=a[k].next)dfs(a[k].y);
}
int n,K;
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d%d",&n,&K);
root=LA=++cnt;
for(int i=1;i<=n;i++)
{
scanf("%s",ch+1);
int ln=strlen(ch+1);LA=root;T++;
for(int j=1;j<=ln;j++)add(ch[j]-'a'),hh[i].push_back(ch[j]-'a');
}
for(int i=1;i<=cnt;i++)ins(tr[i].parent,i),f[i]=((ct[i]>=K)?(tr[i].dep-tr[tr[i].parent].dep):(0));
// for(int i=1;i<=cnt;i++)printf("%d ",ct[i]);
dfs(1);
for(int i=1;i<=n;i++)
{
LL ans=0;
for(int p=root,j=0;j<hh[i].size();j++)ans+=f[p=tr[p].son[hh[i][j]]];
printf("%lld ",ans);
}
puts("");
return 0;
}