I Love Palindrome String

 I Love Palindrome String

时间限制: 2 Sec  内存限制: 128 MB

题目描述

You are given a string S=s1s2..s|S| containing only lowercase English letters. For each integer i∈[1,|S|] , please output how many substrings slsl+1...srsatisfy the following conditions:
 ∙ r−l+1 equals to i.
 ∙ The substring slsl+1...sr is a palindrome string.
 ∙ slsl+1...s⌊(l+r)/2⌋ is a palindrome string too.
|S| denotes the length of string S.
A palindrome string is a sequence of characters which reads the same backward as forward, such as madam or racecar or abba. 

输入

There are multiple test cases.
Each case starts with a line containing a string S(1≤|S|≤3×105) containing only lowercase English letters.
It is guaranteed that the sum of |S| in all test cases is no larger than 4×106.

输出

For each test case, output one line containing |S| integers. Any two adjacent integers are separated by a space.

样例输入

abababa

样例输出

7 0 0 0 3 0 0

题意:求有多少个字符串为回文串,且它的前一半也是回文串。
回文树+马拉车。先用回文树求出全部的本质不一样(就是长度不一样,或者长度一样内容不一样)的字符串,然后用马拉车快速判断该串是不是符合题意。
#include<bits/stdc++.h>
using namespace std;
//https://www.xuebuyuan.com/3184341.html
const int MAXN = 300005 ;
const int N = 26 ;
 
int Palindromic_Length[MAXN*2];
int ans[MAXN];
 
 
struct Palindromic_Tree
{
    int nxt[MAXN][26],f[MAXN],cnt[MAXN],num[MAXN],len[MAXN],c[MAXN],last,n,L;
 
    int l[MAXN],r[MAXN];
 
    inline int newnode(int x)
    {
        for(register int i=0; i<26; ++i)
            nxt[L][i]=0;
        cnt[L]=0;
        len[L]=x;
        return L++;
    }
    void init()
    {
        L=0;
        newnode(0);
        newnode(-1);
        last=0;
        n=0;
        c[n]=-1;
        f[0]=1;
    }
    inline int getf(int x)
    {
        while(c[n-len[x]-1]!=c[n])
            x=f[x];
        return x;
    }
    inline void add(int x)
    {
        x-='a';
        c[++n]=x;
        int cur=getf(last);
        if(!nxt[cur][x])
        {
            int now=newnode(len[cur]+2);
 
             l[now]=n-len[cur]-1;
            r[now]=n;
 
            f[now]=nxt[getf(f[cur])][x];
            nxt[cur][x]=now;
        }
        ++cnt[last=nxt[cur][x]];
    }
    void count()
    {
        for(register int i=L-1; i>=2; --i)
            cnt[f[i]]+=cnt[i];
    }
 
    void getans()
    {
        count();
        for(int i=2;i<L;i++)
        {
            int l1=l[i],r1=r[i];
            r1=(l1+r1)/2;
 
            r1*=2;
            l1*=2;
 
            int mid=(r1+l1)/2;
 
            if(mid-Palindromic_Length[mid]+1<=(l1))
            {
                ans[len[i]]+=cnt[i];
            }
        }
    }
 
 
} PT;
 
string Manacher(string s)
{
    /*改造字符串*/
    string res="$#";
    for(int i=0; i<s.size(); ++i)
    {
        res+=s[i];
        res+="#";
    }
 
    /*数组*/
    vector<int> P(res.size(),0);
    int mi=0,right=0;   //mi为最大回文串对应的中心点,right为该回文串能达到的最右端的值
    int maxLen=0,maxPoint=0;    //maxLen为最大回文串的长度,maxPoint为记录中心点
 
    for(int i=1; i<res.size(); ++i)
    {
        P[i]=right>i ?min(P[2*mi-i],right-i):1;     //关键句,文中对这句以详细讲解
 
        while(res[i+P[i]]==res[i-P[i]])
            ++P[i];
 
        if(right<i+P[i])    //超过之前的最右端,则改变中心点和对应的最右端
        {
            right=i+P[i];
            mi=i;
        }
 
        if(maxLen<P[i])     //更新最大回文串的长度,并记下此时的点
        {
            maxLen=P[i];
            maxPoint=i;
        }
        Palindromic_Length[i]=P[i]-1;
 
       // printf("%d %d %c\n",i,P[i]-1,res[i]);
 
    }
    return s.substr((maxPoint-maxLen)/2,maxLen-1);
}
 
Palindromic_Tree tree;
int main()
{
    char s[MAXN];
 
    while(scanf("%s",s)==1)
    {
        string a(s);
        tree.init();
 
        int len=strlen(s);
        for(int i=0;i<len;i++)tree.add(s[i]),ans[i+1]=0;
        Manacher(a);
        tree.getans();
        for(int i=1;i<=len;i++)printf("%d%c",ans[i],i==len ? '\n' : ' ');
    }
    //for(int i=0;i<a.size();i++)tree.add(a[i]);
    return 0;
 
}
View Code
posted @ 2019-07-27 10:43  1371767389  阅读(339)  评论(0编辑  收藏  举报