#1589 : 回文子串的数量(Manacher)

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

给定一个字符串S,请统计S的所有|S| * (|S| + 1) / 2个子串中(首尾位置不同就算作不同的子串),有多少个是回文字符串?

输入

一个只包含小写字母的字符串S。

对于30%的数据,S长度不超过100。

对于60%的数据,S长度不超过1000。

对于100%的数据,S长度不超过800000。

输出

回文子串的数量

样例输入
abbab
样例输出
          8

manacher算法,可以直接求出
i 枚举中心位置,p[i] 记录i下标为中心的最长回文串半径,
id记录已匹配的回文串中点下标,mx记录已匹配的回文串的右边界下标+1

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define MOD 1000000007
#define MX 800050

int len;
char temp[MX];
char str[MX*2];
int p[MX*2];
LL ans;

void Init()
{
    len = 0, ans = 0;
    str[len++]='!';
    str[len++]='#';
    int t = strlen(temp);
    for (int i=0;i<t;i++)
    {
        str[len++]=temp[i];
        str[len++]='#';
    }
    memset(p,0,sizeof(p));
}

void Manacher()
{
    int mx = 0, id =0;
    for (int i=1;i<len;i++)
    {
        p[i] = mx>i ? min(p[2*id-i],mx-i):1;
        while (i-p[i]>=0 && str[i+p[i]]==str[i-p[i]]) p[i]++;
        ans+=p[i]/2;
        if (i+p[i]>mx)
        {
            mx = i+p[i];
            id = i;
        }
    }
}

int main()
{
    while (scanf("%s",temp)!=EOF)
    {
        Init();
        Manacher();
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

 
posted @ 2017-09-26 16:17  happy_codes  阅读(288)  评论(0编辑  收藏  举报