BZOJ-3473/3277: 字符串

[文章目录]

Description

给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串?n,k<=10^5

和上一题一样,建广义后缀自动机,标记每个点表示的串的集合,之后直接搜索后缀树吧2333,复杂度O(n√n)
不然的话可以树链的并+线段树维护dfs出栈-1入栈+1+树链的并复杂度nlogn【其实n是广义SAM的点数】

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 101000 
typedef long long ll;
ll siz[N<<1];
int n,m,l[N],r[N];
char st[N];
int last,tot=1,ch[N<<1][26],pre[N<<1],dep[N<<1],vis[N<<1],ws[N<<1],sa[N<<1];
void insert(int x)
{
    int p=last;
    if(ch[p][x])
    {
        int q=ch[p][x];
        if(dep[q]==dep[p]+1) last=q;
        else
        {
            int clo=++tot; last=clo;
            memcpy(ch[clo],ch[q],sizeof(ch[q]));
            pre[clo]=pre[q],dep[clo]=dep[p]+1,pre[q]=clo;
            for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=clo;
        }
    }
    else
    {
        int cur=++tot;
        last=cur; dep[cur]=dep[p]+1;
        for(;p&&!ch[p][x];p=pre[p]) ch[p][x]=cur;
        if(!p) pre[cur]=1;
        else
        {
            int q=ch[p][x];
            if(dep[q]==dep[p]+1) pre[cur]=q;
            else
            {
                int clo=++tot;
                memcpy(ch[clo],ch[q],sizeof(ch[q]));
                dep[clo]=dep[p]+1,pre[clo]=pre[q],pre[q]=pre[cur]=clo;
                for(;p&&ch[p][x]==q;p=pre[p]) ch[p][x]=clo;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int i,j,k,p;
    for(i=1;i<=n;++i)
    {
        l[i]=r[i-1]+1;
        scanf("%s",st+l[i]);
        r[i]=strlen(st+1);
        for(last=1,j=l[i];j<=r[i];++j) insert(st[j]-'a');
    }
    for(i=1;i<=n;++i)
        for(p=1,j=l[i];j<=r[i];++j)
        {
            p=ch[p][st[j]-'a'];
            for(k=p;k&&vis[k]!=i;k=pre[k]) siz[k]++,vis[k]=i;
        }
    for(i=1;i<=tot;++i) ws[dep[i]]++;
    for(i=1;i<=tot;++i) ws[i]+=ws[i-1];
    for(i=1;i<=tot;++i) sa[ws[dep[i]]--]=i;
    for(siz[1]=0,i=2;i<=tot;++i) siz[sa[i]]=siz[pre[sa[i]]]+(siz[sa[i]]>=m)*(dep[sa[i]]-dep[pre[sa[i]]]);
    long long ans;
    for(i=1;i<=n;++i)
    {
        ans=0;
        for(p=1,j=l[i];j<=r[i];++j) p=ch[p][st[j]-'a'],ans+=siz[p];
        printf("%lld ",ans);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注