2015 UESTC Training for Search Algorithm & String - M - Palindromic String【Manacher回文串】

O(n)的复杂度求回文串:Manacher算法

 

定义一个回文值,字符串S是K重回文串,当且仅当S是回文串,且其长度为N/2的前缀和长度为N/2的后缀是K1重回文串

现在给一个2*10^6长度的字符串,求其每个前缀的最大回文值之和。

 

设dp[i]为长度为i的前缀的最大回文值。

当长度为i的前缀的字符串是回文串的时候,有:dp[i]=dp[i/2]+1

若不是回文串 dp[i]=0

 

接下来就是怎么样快速的判断回文串了,推荐算法Manacher算法。

Manacher算法先对字符串进行修改 如 aba -> $#a#b#a#

那么该怎么用DP求?

 

显然一下几点是满足的:

如果某个前缀是回文串,该前缀的末端一定是字符#,(因为第一个符号是#)

故对于不是字符#的位置,它的dp值一定为0

如果最大延伸数组p[i]=i,即向左正好延伸到最左边,那么1~p[i]+i-1一定是一个回文前缀

若第i位是#号 : dp[mx]=dp[i]  其中mx=p[i]+i-1 

对于不是#的情况 : dp[mx]=dp[i-1] 其中mx=p[i]+i-1

#include<bits/stdc++.h>
#define eps 1e-9
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define MAXN 4000005
#define MAXM 40005
#define INF 0x3fffffff
#define PB push_back
#define MP make_pair
#define X first
#define Y second
#define lc (k<<1)
#define rc ((k<<1)1)
using namespace std;
typedef long long LL;
int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
bool flag;

int p[MAXN],dp[MAXN];
char str[MAXN],s[MAXN];

void kp()
{
    int i;
    int mx = 0;
    int id;
    for(i=n; str[i]!=0; i++)//清除n后边多余的部分
        str[i] = 0; //没有这一句有问题。。就过不了ural1297,比如数据:ababa aba
    for(i=1; i<n; i++)
    {
        if( mx > i )
            p[i] = min( p[2*id-i], p[id]+id-i );
        //因为是从左往右扫描的这里i>id, 2*id-i是i关于id的对称点,该对称点在id的左端
        //p[id]+id是描述中的mx,即id向右延伸的端点位置
        //显然向右延伸是可能超出mx的,所以要有下边的for循环
        else
            p[i] = 1;
        for(; str[i+p[i]] == str[i-p[i]]; p[i]++);

        if( p[i] + i > mx )//更新mx与id,因为mx是向右延伸的最大长度,所以实时更新
        {
            mx = p[i] + i;
            id = i;
        }
    }
}

void init()//处理字符串
{
    int i, j, k;
    str[0] = '$';
    str[1] = '#';
    for(i=0; i<n; i++)
    {
        str[i*2+2] = s[i];
        str[i*2+3] = '#';
    }
    n = n*2+2;
    s[n] = 0;
}

int main()
{
    scanf("%s",s);
    n=strlen(s);
    init();
    kp();
    for (i=2;i<n;i++)
    {
        if (p[i]==i)
        {
            int mx=p[i]+i-1;
            if (str[i]!='#')
            {
                dp[mx]=max(dp[mx],dp[i-1]+1);
            }else
                dp[mx]=max(dp[mx],dp[i]+1);
        }
    }
    int sum=0;
    for (i=0;i<n;i++) sum+=dp[i];
    printf("%d\n",sum);
    return 0;
}

 

 

posted @ 2015-05-04 21:21  zhyfzy  阅读(200)  评论(2编辑  收藏  举报