题目大意:给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身)
题解:SA有比较厉害的做法,可惜我没听懂……
广义SAM也可以做……Orz Candy?
我的收获:广义SAM get……
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long ll;
int n,k,u;
string s[N>>1];
char ss[N>>1];
ll f[N],ans;
struct Suffix_Automation{
int cnt,last,root;
int ch[N][26],fail[N];
int mx[N],cou[N],cur[N];
Suffix_Automation(){cnt=1,last=1,root=1;}
void expend(int c){
int p=last,np=last=++cnt;
mx[np]=mx[p]+1;
for(;p&&!ch[p][c];p=fail[p]) ch[p][c]=np;
if(!p) fail[np]=root; else{
int q=ch[p][c];
if(mx[p]+1==mx[q]) fail[np]=q; else{
int nq=++cnt;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fail[nq]=fail[q],fail[np]=fail[q]=nq;
for(;ch[p][c]==q;p=fail[p]) ch[p][c]=nq;
}
}
}
int a[N],sc[N];
void RadixSort(){
for(int i=1;i<=cnt;i++) sc[mx[i]]++;
for(int i=1;i<=cnt;i++) sc[i]+=sc[i-1];
for(int i=cnt;i>=1;i--) a[sc[mx[i]]--]=i;
}
void walk(){
for(int i=1;i<=n;i++){
u=root;
for(int j=0;j<s[i].size();j++){
u=ch[u][s[i][j]-'a'];
for(int p=u;p&&cur[p]!=i;p=fail[p]) cou[p]++,cur[p]=i;
}
}
}
void ask(){
for(int i=1;i<=cnt;i++) u=a[i];
cou[1]=0;
for(int i=1;i<=cnt;i++) u=a[i],f[u]=f[fail[u]]+(cou[u]>=k?mx[u]-mx[fail[u]]:0);
for(int i=1;i<=n;i++){
u=root;ans=0;
for(int j=0;j<s[i].size();j++) u=ch[u][s[i][j]-'a'],ans+=f[u];
printf("%lld ",ans);
}
putchar('\n');
}
}SAM;
void work()
{
SAM.walk();
SAM.RadixSort();
SAM.ask();
}
void init()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%s",ss);s[i]=string(ss);//it's sad that the maxlength was unknown
SAM.last=SAM.root;
for(int j=0;j<s[i].size();j++) SAM.expend(s[i][j]-'a');
}
}
int main()
{
init();
work();
return 0;
}
本文介绍了一种使用广义Suffix Automation (SAM) 解决特定字符串子串问题的方法。给定n个字符串,文章探讨了如何计算每个字符串中有多少子串是至少k个字符串的公共子串。通过详细的代码解析,读者可以了解到广义SAM的实现细节及如何高效地处理此类问题。
3626

被折叠的 条评论
为什么被折叠?



