hdu6194求出现恰好k次的子串数量

题:http://acm.hdu.edu.cn/showproblem.php?pid=6194

题意:求出现恰好k次的子串数量

分析:也就是f数组==k的maxlen[i]-maxlen[ slink[i] ]的总和;  

   因为f数组表示endpos的集合大小,也就是状态在多少个位置出现过,那么这个状态的所有子串maxlen[i]-maxlen[slink[i]]个都出现过几次

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const int M=1e5+3;
int trans[M<<1][26],slink[M<<1];
ll maxlen[M<<1];
ll f[M<<1];
int last,tot,root;
char s[M];
int que[M<<1],in[M<<1];
int k;
ll res=0;
void init(){
    tot=last=root=1;
    memset(in,0,sizeof(in));
    memset(f,0,sizeof(f));
    memset(trans,0,sizeof(trans));
    memset(slink,0,sizeof(slink));
    memset(maxlen,0,sizeof(maxlen));
}
void extend(int c){
    maxlen[++tot]=maxlen[last]+1;
    int p=last,np=tot;
    f[np] = 1;///maxlen的串为主串的前缀时才为1
    while(p&&!trans[p][c]){
        trans[p][c]=np;
        p=slink[p];
    }
    ///在之前构造的sam中出现了现在的后缀
    if(!p)
        slink[np]=root;
    else{
        int q=trans[p][c];
        if(maxlen[p]+1!=maxlen[q]){///若p+c不是q中最大的字符串,
            ///新建个克隆节点,把p+c从q中挑出来
            maxlen[++tot]=maxlen[p]+1;
            int nq=tot;
            memcpy(trans[nq],trans[q],sizeof(trans[q]));
            slink[nq]=slink[q];
            slink[q]=slink[np]=nq;
            while(p&&trans[p][c]==q){
                trans[p][c]=nq;
                p=slink[p];
            }
        }
        else///否则np直接link连接q
            slink[np]=q;
    }
    last=np;
}

void tuopu(){
    int l=1,r=0;
    for(int i=root+1;i<=tot;i++)in[slink[i]]++;
    for(int i=root+1;i<=tot;i++)if(!in[i]) que[++r]=i;
    while(l<=r){
        int x=que[l++];
        f[slink[x]]+=f[x];
        if(--in[slink[x]]==0)
            que[++r]=slink[x];

    }
    for(int i=root+1;i<=tot;i++)
        if(f[i]==k)
            res+=maxlen[i]-maxlen[slink[i]];
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        res=0;
        scanf("%d%s",&k,s+1);
        init();
        int n=strlen(s+1);
        for(int i=1;i<=n;i++)
            extend(s[i]-'a');
        tuopu();
        printf("%lld\n",res);
    }

    return 0;
}
View Code

 

posted @ 2020-12-09 22:46  starve_to_death  阅读(103)  评论(0编辑  收藏  举报