ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

hdu 6599(回文树)

2019-07-24 18:52:43  阅读:291  来源: 互联网

标签:hdu int 6599 len maxn str pam 回文


传送门

题意:

给你一个长度为\(n\)的字符串,现在问你长度为\(1,2\dots n\)的子串中,有多少个子串\(str\)是回文串,且它的长度缩短到$\lceil \frac{|str|}{2} \rceil $后也是回文串。

分析:

很明显我们可以分别利用回文树中的\(cnt\)数组和\(fail\)数组,把任意长度为\(len\)的字符串的回文子串和它的最长回文后缀在\(\mathcal{O}(n)\)的时间处理出来。知道如何去求出上述的东西之后,我们只需要考虑如何去剔除一些不合法的回文子串。

对于一个回文串\(str\),想让他的前一半回文相当于让他后一半回文,那么如果他的最长回文后缀长度小于\(\frac{|str|}{2}\),显然是不行的,所以考虑最长回文后缀长度大于等于\(\frac{|str|}{2}\)的情况。我们发现如果想让它的后一半回文,那么就是要缩短删掉若干个原串和最长回文后缀的差,因此我们只需要判断$\lfloor \frac{|str|}{2} \rfloor$ 是否能够整除 \((|str|-|str_{maxsuffix}|)\)即可

代码:

#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 Ans[maxn];
bool judge(int x,int Len){
    int tmp1=pam.len[pam.fail[x]];
    int tmp2=pam.len[x]-tmp1;
    if((pam.len[x]/2)%tmp2==0) return true;
    else return false;
}
int main()
{
    while(~scanf("%s",str)){
        pam.init();
        int len=strlen(str);
        for(int i=0;i<=len;i++){
            Ans[i]=0;
        }
        for(int i=0;i<len;i++){
            pam.Insert(str[i]);
        }
        pam.getsum();
        ll res=0;
        for(int i=2;i<pam.id;i++){
            if(judge(i,(pam.len[i]+1)/2)){
                Ans[pam.len[i]]+=pam.cnt[i];
            }
        }
        for(int i=1;i<=len;i++){
            if(i==1) printf("%d",Ans[i]);
            else printf(" %d",Ans[i]);
        }
        puts("");
    }
    return 0;
}

标签:hdu,int,6599,len,maxn,str,pam,回文
来源: https://www.cnblogs.com/Chen-Jr/p/11240112.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有