• 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
    ",res);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    JS内容左右滑动
    JS返回上一页
    两栏 三栏的css
    舅舅去世
    .net学习开始
    以论坛管理的方式来处理公司资讯
    《尽管去做》摘
    网页视频播放器代码集
    火影忍者和海贼王
    古代风水文献
  • 原文地址:https://www.cnblogs.com/starve/p/14111453.html
Copyright © 2020-2023  润新知