Codeforces Beta Round #7 D. Palindrome Degree manacher算法+dp

题目链接:

http://codeforces.com/problemset/problem/7/D

D. Palindrome Degree

time limit per test1 second
memory limit per test256 megabytes
#### 问题描述 > 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. #### 输入 > 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 the only number — the sum of the polindrome degrees of all the string's prefixes.

样例输入

a2A

样例输出

1

样例输入

abacaba

样例输出

6

题意

假设前缀prei是k-回文串(k=a[i])。则求ans=sigma(a[i])。

题解

用manacher算法处理出最左端为第一个字母的所有回文串,然后dp一下。
dp[i]表示长度为i的前缀是k-回文串(k=dp[i])。 则dp[i]=dp[i/2]+1;
ans=sigma(dp[i]);

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef long long  LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=1e7+10;

char s[maxn];
//P[i]表示把回文串折叠起来的长度
//mx表示当前计算出来的回文串往右延伸的最远端
//d表示贡献出mx的串的回文中心
int P[maxn],mx,id,n;
LL dp[maxn];

LL solve(){
    LL ret=0;
    int len=strlen(s+1);
    n=len*2+1;
    s[0]='$',s[n]='#',s[n+1]='\0';
    for(int i=len*2;i>=1;i--){
        if(i&1) s[i]='#';
        else s[i]=s[i/2];
    }
//    puts(s);
    clr(dp,0);
    mx=1,id=0;
    for(int i=1;i<=n;i++){
        //优化的核心,画画图比较好理解,j=2*id-i表示i关于id对称的点
        P[i]=mx>i?min(mx-i,P[2*id-i]):1;
        int k=i+P[i];
        while(s[k]==s[2*i-k]) k++,P[i]++;
        if(2*i-k==0&&i>1){
//            bug(i);
            int l=P[i]-1;
            dp[l]=dp[l/2]+1;
            ret+=dp[l];
        }
        if(k>mx){
            mx=k;
            id=i;
        }
    }
    return ret;
}

int main() {
    scf("%s",s+1);
    LL ans=solve();
    prf("%I64d\n",ans);
    return 0;
}

//end-----------------------------------------------------------------------
posted @ 2016-09-06 01:28  fenicnn  阅读(301)  评论(0编辑  收藏  举报