codeforces7D Palindrome Degree(manacher&dp或Hsh&dp)

D. Palindrome Degree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

String s of length n is called k-palindrome, if it is a palindrome itself, and its prefix and suffix of length  are(k - 1)-palindromes. By definition, any string (even empty) is 0-palindrome.

Let's call the palindrome degree of string s such a maximum number k, for which s is k-palindrome. For example, "abaaba" has degree equals to 3.

You are given a string. Your task is to find the sum of the palindrome degrees of all its prefixes.

Input

The first line of the input data contains a non-empty string, consisting of Latin letters and digits. The length of the string does not exceed 5·106. The string is case-sensitive.

Output

Output the only number — the sum of the polindrome degrees of all the string's prefixes.

Sample test(s)
input
a2A
output
1
input
abacaba
output
6

题意:

定义回文串的度为length 即前半部分串的度或后半部分的度+1。先再给你一个字符串。要你求出他所有前缀度的和。

思路:

先用manacher求出以每个位置为中心最大回文串的长度。dp[i]记录长度为i的前缀的度。那么dp[i+1]分奇偶用到前面的度就行了。

详细见代码:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5110000;
int p[maxn<<1],dp[maxn],len;
char buf[maxn],st[maxn<<1];
void init()
{
    int i;
    len=strlen(buf);
    st[0]='$',st[1]='#';
    for(i=0;i<len;i++)
        st[2*i+2]=buf[i],st[2*i+3]='#';
    len=2*len+2;
}
void manacher()
{
    int i,id,mx=0;
    for(i=1;i<len;i++)
    {
        p[i]=mx>i?min(mx-i,p[2*id-i]):1;
        while(st[i+p[i]]==st[i-p[i]])
            p[i]++;
        if(i+p[i]>mx)
            mx=i+p[i],id=i;
    }
}
int main()
{
    int i,ans,n;
    while(~scanf("%s",buf))
    {
        ans=0,n=strlen(buf);
        init();
        manacher();
        ans=dp[0]=1;
        for(i=1;i<n;i++)
        {
            if(p[i+2]-1>=i+1)//判断该前缀是否回文。字符串从0开始。i+2为0到i在p数组对称中心不管回文串长度使是奇数还是偶数的。p[i]-1为最大回文长度
            {
                if(i&1)
                    dp[i]=dp[i/2]+1;
                else
                    dp[i]=dp[i/2-1]+1;
            }
            ans+=dp[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

Hash的做法就比较简单了。

详细见代码:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5110000;;
unsigned long long H1[maxn],H2[maxn],xp[maxn],ha,hb,x=123;
int dp[maxn],len;
char buf[maxn],rbuf[maxn];
void init()
{
    int i;
    len=strlen(buf);
    H1[len]=H2[len]=0;
    xp[0]=1;
    for(i=len-1;i>=0;i--)
    {
        H1[i]=H1[i+1]*x+buf[i];
        H2[i]=H2[i+1]*x+rbuf[i];
        xp[len-i]=xp[len-i-1]*x;
    }
}
unsigned long long getHash(unsigned long long *HS,int s,int L)
{
    return HS[s]-HS[s+L]*xp[L];
}
int main()
{
    int i,ans;
    while(~scanf("%s",buf))
    {
        ans=0,len=strlen(buf);
        for(i=0;i<len;i++)
            rbuf[i]=buf[len-i-1];
        init();
        ans=dp[0]=1;
        for(i=1;i<len;i++)
        {
            ha=getHash(H1,0,i+1);
            hb=getHash(H2,len-i-1,i+1);
            if(ha==hb)
            {
                if(i&1)
                    dp[i]=dp[i/2]+1;
                else
                    dp[i]=dp[i/2-1]+1;
            }
            else
                dp[i]=0;
            ans+=dp[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值