• C Count New String(SAM建立n个子串)


    题:https://ac.nowcoder.com/acm/contest/5669/C

    题解:

    分析:核心点1:当我们把原串第一次进行f函数后,第二次的f函数一定是对第一次经过f函数后的串进行取子串。

       核心点2:因为f函数的特性,这n个子串我们可以以10(字符集)*N的节点代价来建立字典树,考虑题解的俩个位置i,j,我们只需要记录插入 j 的last值,在插入时就插入到这个last值后面(tire树后面)(要插入j-i个)。

            这里只用插入j-i个的理由:按照核心点1的求法,我们可能要求插入(j-i)-1,插入(j-i)-2...长度允许的话,但大可不必,因为在统计不同子串的时候,最长的(插入(j-i)个)的个数已经全涵盖了当前(插入(j-i)-1,插入(j-i)-2...) 的所有子串。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int M=1000006;
    int trans[M<<1][26],slink[M<<1],maxlen[M<<1];
    int endpos[M<<1];
    int last,now,root,len;
    
    void init(){
        now=last=root=1;
    }
    void extend(int c){
        maxlen[++now]=maxlen[last]+1;
        int p=last,np=now;
        while(p&&!trans[p][c]){
            trans[p][c]=np;
            p=slink[p];
        }
        if(!p)
            slink[np]=root;
        else{
            int q=trans[p][c];
            if(maxlen[p]+1!=maxlen[q]){
                maxlen[++now]=maxlen[p]+1;
                int nq=now;
                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
                slink[np]=q;
        }
        last=np;
        endpos[np]=1;
    }
    int pos[20],lastpos[M];
    char s[M];
    int main(){
        scanf("%s",s+1);
        init();
        int len=strlen(s+1);
        reverse(s+1,s+1+len);
        lastpos[0]=1;
        for(int i=1;i<=len;i++){
            last=lastpos[pos[s[i]-'a']];
            for(int j=pos[s[i]-'a']+1;j<=i;j++){
                extend(s[i]-'a');
                lastpos[j]=last;
            }
            for(int j=0;j<=s[i]-'a';j++)
                pos[j]=i;
        }
        ll ans=0;
        for(int i=root+1;i<=now;i++)
            ans+=maxlen[i]-maxlen[slink[i]];
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    补充:sam的板子的last值是默认上一位的状态值,因为模板只用对一个字符串进行操作,而对多个串进行建sam时可以依据字符集的大小记录最后插入的last,每次插入时可直接在记录的last插入。

  • 相关阅读:
    gdb简易教程
    使用WoeUSB在Linux上制作Win10启动盘
    How to fix git: new blank line at EOF
    使用CSS3动画属性实现各种旋转跳跃
    jQuery事件
    挖矿程序minerd入侵分析和解决办法
    css3的伪(伪类和伪元素)大合集
    HTML 5 <blockquote><p>的分工与合作
    HTML<figure> <figcaption> 标签定义图文并茂
    监听 返回按钮事件
  • 原文地址:https://www.cnblogs.com/starve/p/13354778.html
Copyright © 2020-2023  润新知