• BZOJ 3676(回文树模板题)


    传送门

    题面:

    3676: [Apio2014]回文串

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 3755  Solved: 1755
    [Submit][Status][Discuss]

    Description

    考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 
    现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最 
    大出现值。 

    Input

    输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。 

    Output


    输出一个整数,为逝查回文子串的最大出现值。 

    Sample Input

    【样例输入l】
    abacaba

    【样例输入2]
    www

     

    Sample Output

    【样例输出l】
    7

    【样例输出2]
    4

    HINT

    一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。 

    在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中: 

    ● a出现4次,其出现值为4:1:1=4 

    ● b出现2次,其出现值为2:1:1=2 

    ● c出现1次,其出现值为l:1:l=l 

    ● aba出现2次,其出现值为2:1:3=6 

    ● aca出现1次,其出现值为1=1:3=3 

    ●bacab出现1次,其出现值为1:1:5=5 

    ● abacaba出现1次,其出现值为1:1:7=7 

    故最大回文子串出现值为7。 

    【数据规模与评分】 

    数据满足1≤字符串长度≤300000。

    题目分析:

        回文树模板题。首先需要了解回文树的含义

        知道了回文树的含义后,我们很明显可以发现,事实上题目中要我们求的就是长度为i的字符串的本质不同的回文字串的个数num,用num*i即为最终的答案。

        因此我们只需要将字符串建一颗回文树,之后按fail边自下而上更新一下即可

        最后只需要输出它们当中最大的。

    代码:

    #include <bits/stdc++.h>
    #define maxn 300005
    using namespace std;
    char str[maxn];
    typedef long long ll;
    struct PAM{//回文树
        int next[maxn][26],fail[maxn],len[maxn],cnt[maxn],S[maxn];
        int id,n,last;
        int newnode(int x){
            for(int i=0;i<26;i++){
                next[id][i]=0;
            }
            cnt[id]=0;
            len[id]=x;
            return id++;
        }
        void init(){
            id=0;
            newnode(0);
            newnode(-1);
            fail[0]=1;
            S[0]=-1;
            last=n=0;
        }
        int getfail(int x){
            while(S[n-len[x]-1]!=S[n]) x=fail[x];
            return x;
        }
        void Insert(int c){
            c-='a';
            S[++n]=c;
            int cur=getfail(last);
            if(!next[cur][c]){
                int now=newnode(len[cur]+2);
                fail[now]=next[getfail(fail[cur])][c];
                next[cur][c]=now;
            }
            last=next[cur][c];
            cnt[last]++;
        }
        void getsum(){//自下向上更新
            for(int i=id-1;i>=0;i--){
                cnt[fail[i]]+=cnt[i];
            }
        }
    }pam;
    int main()
    {
        scanf("%s",str);
        pam.init();
        int len=strlen(str);
        for(int i=0;i<len;i++){
            pam.Insert(str[i]);
        }
        pam.getsum();
        ll res=0;
        for(int i=2;i<pam.id;i++){
            res=max(res,1ll*pam.len[i]*pam.cnt[i]);
        }
        cout<<res<<endl;
    }
    
  • 相关阅读:
    读书笔记
    STL 笔记
    Centos8如何配置网桥
    命令集合
    shared_ptr给管理的对象定制析沟函数
    share_ptr指向的对象的析构动作在创建的时候被捕获
    优秀博客
    字符串单词翻转
    带权图的最短路径算法(Dijkstra,Floyd,Bellman_ford)
    生产者与消费者 c++实现
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007209.html
Copyright © 2020-2023  润新知