UESTC 1066 Palindromic String manacher

来源:互联网 发布:火车头采集软件下载 编辑:程序博客网 时间:2024/06/15 16:18

Palindromic String

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 128000/128000KB (Java/Others)


Submit  Status
秋实大哥喜欢探索新鲜事物,最近他发明了一种新型回文串,叫K重回文串!今天他想用它来考考小朋友们。
秋实大哥给出了与K重回文串有关的信息
任何字符串都属于0重回文串,包括空字符串。
一个长度为N的字符串S,S是K(k≥1)重回文串,当且仅当S是回文串,且其长度为⌊N2⌋的前缀和长度为⌊N2⌋的后缀是K−1重回文串。
如果一个字符串是K重回文串,则称该字符串有一个回文值为K。一个字符串可以有多个回文值,比如S=abaaba,其回文值可为0,1,2,3。
字符串的最大回文值是该字符串所有回文值的最大值。
若字符串S的最大回文值≥1,则S一定是回文串。
一个字符串S,如果其正着读和反着读是一样的,则称S是回文串,比如aabaa,aba,a。但abc,abab,aacba就不是回文串。
一个长度为N的字符串S,其有N+1个前缀和N+1个后缀(不一定非空),比如abcde,有6个前缀,分别是空字符串,a,ab,abc,abcd,abcde;有6个后缀,分别是空字符串,e,de,cde,bcde,abcde。
秋实大哥给你一个字符串S,他想问问你,S所有前缀的最大回文值之和是多少?


Input

第一行输入一个字符串S(0<|S|≤2⋅106),S包含 大写英文字母(A-Z),小写英文字母(a-z),数字(0-9)


Output

输出一个整数,表示S所有前缀的最大回文值之和。


Sample input and output

Sample Input                                                                                         Sample Output
z                                                                                                                           1
a2Az                                                                                                                    1
abacaba                                                                                                             6
CCeCeCCCee                                                                                                  4

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ             231


Hint

下面对样例3进行解释:
abacaba有8个前缀,分别是 空字符串,a,ab,aba,abac,abaca,abacab,abacaba;
设P(i) 表示第 i 个前缀的最大回文值,且空字符串是第0个前缀;
则P(0)=0,P(1)=1,P(2)=0,P(3)=2,P(4)=0,P(5)=0,P(6)=0,P(7)=3;那么∑7i=0P(i)=6∑i=07P(i)=6。


Source

2015 UESTC Training for Search Algorithm and String

UESTC 1066 Palindromic String


My Solution

题意:求出前缀的回文重数的和,(回文重数是递归定义的,详见题面)。

manacher
先用manacher跑出所有的回文子串,并把[i,j]的回文子串半径大小存储在了len[i+j]里,
然后从做到右跑一遍,且同时用f[i]表示0~i的回文子串重数,
每次
if(f[(i+1)/2-1] && len[i] >= i/2+1){
    f[i] = f[(i+1)/2-1] + 1;
    ans += f[i];
}
else if(len[i] >= i/2+1){
    f[i] = 1;
    ans += f[i];
}
时间复杂度 O(n)
空间复杂度 O(n)


#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long LL;const int MAXN = 2e6 + 8;int len[2*MAXN];char str[MAXN];void manacher(int n){    int p, q, r;    len[0] = 1;    for(int i = 1, j = 0; i < (n << 1) - 1; i++){        p = i >> 1, q = i - p, r = ((j + 1) >> 1) + len[j] - 1;        len[i] = r < q ? 0 : min(r - q + 1, len[(j << 1) - i]);        while(p > len[i] - 1 && q + len[i] < n && str[p - len[i]]              == str[q + len[i]])                len[i]++;        if(q + len[i] - 1 > r)            j = i;    }}int f[MAXN];int main(){    #ifdef LOCAL    freopen("e.txt", "r", stdin);    //freopen("e.out", "w", stdout);    int T = 4;    while(T--){    #endif // LOCAL    //ios::sync_with_stdio(false); cin.tie(0);    scanf("%s", str);    int sz = strlen(str), i;    LL ans = 1;    manacher(sz);    f[0] = 1;    for(i = 1; i < sz; i++){        //cout << 0 << " "<< i << " " << len[i] << endl;        if(f[(i+1)/2-1] && len[i] >= i/2+1){            f[i] = f[(i+1)/2-1] + 1;            ans += f[i];        }        else if(len[i] >= i/2+1){            f[i] = 1;            ans += f[i];        }    }    printf("%lld\n", ans);    #ifdef LOCAL    memset(len, 0, sizeof len);    memset(f, 0, sizeof f);    cout << endl;    }    #endif // LOCAL    return 0;}


  Thank you!

                                                                                                                                            ------from ProLights