• 【字符串】回文树学习笔记


    燃鹅,一年后的我在想,回文树是个什么东西?(._."||)

     2020-10-08


    好好理解了回文树。

    理解后的感觉:为啥子之前会觉得很复杂?Orz

    根据自己理解改了个自己能看懂的模板

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+50;
    
    int last,tot,n;
    int nex[maxn][27],len[maxn],fail[maxn],s[maxn],cnt[maxn];
    /*
    n 是字符串的长度
    last 是当前节点的上一节点 记录信息的节点编号从1开始
    next[i][j] 是 i节点左右添加字符x后所形成的新的字符串的 节点标号
    len[i] 是i节点所代表的字符串的长度
    fail[i] 是节点i的最长回文后缀的 节点标号
    s[i] 是字符串的第i个字符
    cnt[i] 是i节点所代表的的回文串在整个字符串里出现的次数
    */
    inline void init()
    {
        s[0]=-1;fail[0]=1;last=0;
        len[0]=0;len[1]=-1;tot=1;
    }
    /*
    零号节点的最长回文后缀是指向1号节点 而1号节点的长度是 len[1]=-1;
    这个操作有利于:
    当添加第一个字符时(节点2) 新的回文串长度 恰好等于:-1+2=1
    */
    inline int getfail(int x,int id)
    {
        while(s[id-len[x]-1]!=s[id])x=fail[x];
        return x;
    }
    /*
    从x节点往下找 找回文后缀恰好回文后缀的前一个字符等于要添加的字符
    使得能构成一个新的回文后缀
    若找不到,则结果是回到1号节点 然后再添加新字符 则形成了一个长度为1的回文串
    len[1]=-1有利于
    在找不到的情况下 最后一定能找到1号节点满足:
    (s[id-len[1]-1]=s[id-(-1)-1])==s[id]
    */
    inline int newnode(int x)
    {
        len[++tot]=x;
        return tot;
    }
    inline int solve()
    {
        int i,p,q=1;
        init();
        for(i=1;i<=n;i++)
        {
            p=getfail(last,i);
            //找到上一节点可以添加s[i]字符的回文后缀所在的节点标号 p
            if(nex[p][s[i]]==0)//如果 p节点没有过两边添加s[i]的记录
            {
                printf("%d %d ",i,q);
                q=newnode(len[p]+2);//新字符串为p串两边添加s[i]
                fail[q]=nex[getfail(fail[p],i)][s[i]];
                //q的最长回文后缀是 p的满足前一个字符是s[i]的回文后缀再加字符s[i]的回文串所在节点 没有则为节点0
                nex[p][s[i]]=q;
    
                for(int j=i-len[q]+1;j<=i;j++)printf("%c",s[j]+'a');
                putchar(10);
            }
            last=nex[p][s[i]];//将当前节点更新到上一节点
            cnt[nex[p][s[i]]]++;//这个回文串出现的记录+1
        }
        for(i=tot;i>1;i--)
        {
            cnt[fail[i]]+=cnt[i];
            /*
            i节点出现必是包含其回文后缀的出现
            所以最后需要更新回文后缀出现的次数
            因为之前更新的节点所代表的串 都不会是别的串的最长回文后缀
            */
        }
    }
    int main()
    {
        char s1[maxn];
        scanf("%s",s1);
        n=strlen(s1);
        for(int i=1;i<=n;i++)s[i]=s1[i-1]-'a';
        solve();
    }

    2019-09-10 22:39:54


    P3649

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+50;
    
    char ss[maxn];
    int last,tot,n;
    int nex[maxn][27],len[maxn],fail[maxn],s[maxn],cnt[maxn];
    inline void init()
    {
        n=strlen(ss);
        for(int i=1;i<=n;i++)s[i]=ss[i-1]-'a';
        s[0]=-1;fail[0]=1;last=0;
        len[0]=0;len[1]=-1;tot=1;
    }
    inline int getfail(int x,int id)
    {
        while(s[id-len[x]-1]!=s[id])x=fail[x];
        return x;
    }
    inline int newnode(int x)
    {
        len[++tot]=x;
        return tot;
    }
    inline void PT()
    {
        int p,q=1;
        init();
        for(int i=1;i<=n;i++)
        {
            p=getfail(last,i);
            if(nex[p][s[i]]==0)
            {
    //            printf("%d %d ",i,q);
                q=newnode(len[p]+2);
                fail[q]=nex[getfail(fail[p],i)][s[i]];
                nex[p][s[i]]=q;
    //            for(int j=i-len[q]+1;j<=i;j++)printf("%c",s[j]+'a');putchar(10);
            }
            last=nex[p][s[i]];
            cnt[nex[p][s[i]]]++;
        }
        for(int i=tot;i>1;i--)cnt[fail[i]]+=cnt[i];
    }
    inline int solve()
    {
        ll ans=0;
        PT();
        for(int i=1;i<=tot;i++)ans=max(ans,(ll)len[i]*cnt[i]);
        printf("%lld
    ",ans);
    }
    int main()
    {
        scanf("%s",ss);
        solve();
    }
  • 相关阅读:
    css如何使背景图片水平居中
    HTML特殊符号显示技巧
    自定义jquery插件
    bootstrap学习以及其插件
    自定义checkbox样式
    maven java.lang.OutOfMemoryError:PermGEn space
    Java多线程学习(吐血超详细总结)
    Maven .m2 setting.xml配置
    html a标签打开邮件
    File 类
  • 原文地址:https://www.cnblogs.com/kkkek/p/11503579.html
Copyright © 2020-2023  润新知