T - Palindrome(manacher+树状数组)

题目

Alice like strings, especially long strings. For each string, she has a special evaluation system to judge how elegant the string is. She defines that a string S[1. .3n−2 ] (n≥2) is one-and-half palindromic if and only if it satisfies S[i]=S[2n−i]=S [2n+i−2] (1≤i≤n).For example, abcbabc is one-and-half palindromic string, and abccbaabc
is not. Now, Alice has generated some long strings. She ask for your help to find how many substrings which is one-and-half palindromic.
Input
The first line is the number of test cases. For each test case, there is only one line containing a string(the length of strings is less than or equal to 500000
), this string only consists of lowercase letters.
Output
For each test case, output a integer donating the number of one-and-half palindromic substrings.
Sample Input

1
ababcbabccbaabc

Sample Output

2

Hint

In the example input, there are two substrings which are one-and-half palindromic strings, abababababab and abcbabcabcbabcabcbabc.

解释

因为 S[1. .3n−2 ] (n≥2),S[i]=S[2n−i]=S [2n+i−2] (1≤i≤n),可以得到1~2n-1是一个回文串,且这是一个奇数串,对称中心为n。另外得到n~3n-2也是一个奇数回文串,对称中心为2n-1。要满足这些条件,就是去在所给的字符串中寻找这两个中心。
设为一个i,另一个j来说明,由于寻找的结果字符串,条件要求都是含有奇数回文串(所以不用管偶数串)。所以使用manacher算法,先求出增长后字符串的len数组,再更新为原字符串的len[i](不用管偶数串),表示以i为中心的回文半径(中心点也算上)。
那么枚举其中每一个回文中心i,则答案求的是在[i,i+len[i]−1]中,有多少个j,j∈[i,i+len[i]−1]且j−len[j]≤i。
例如c b c b c b c ,结果是5,包含两个cbcb,两个bcbc,一个cbcbcbc。由于题目要求是3n-2的长度,所以只能是4,7,10之类的。但我们不关心,我们只在乎两个回文中心,j落在i右边的范围内,j的最左边要小于等于i。(选定一对正确的i , j,其实该条字符串长度是 3*(j-i+1)-2, i为中心能把j包进来, i,j为中心又都是回文,长度必定可以大于等于 3*(j-i+1)-2, 题目要求所以选择 3*(j-i+1)-2)
我们通过vecto从1~lens把j的左边为下标的数组内存入j。然后在1~lens选择 i, 选择i时能抵达1~i-1的j都已经在树状数组里存在,我们只要从中找出在i右边内含右边界上的j数量就好了。 于是有 ans += query(min(lens, i+len[i]-1)) - query(i);注意不包括i是因为如果包括i代表i == j的情况,不符合题意, 会变成一个普通回文串了。
树状数组在这的的作用是快速查询区间和,速度快。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define maxn 500005
#define ll long long
using namespace std;
ll c[maxn];
int lowbit(int x){
    return x&(-x);
}
void updata(int x, int y, int n){
    int i;
    for(i = x; i <= n; i += lowbit(i))
        c[i] += y;
}
ll query(int x){
    int i;
    ll ans = 0;
    for(i = x; i; i -= lowbit(i))
        ans += c[i];
    return ans;
}
char s[maxn], str[maxn*2];
int lens;
void inint(char *s){
    int i;
    str[0] ='@';
    for(i = 1; i <= lens*2; i += 2){
        str[i] ='#';
        str[i+1] =s[i/2];
    }
    str[2*lens+1] = '#';
    str[2*lens+2] = '$';
}
int len[500005*2];
void manacher(int n){
    int i, po = 0, mx = 0;
    for(i = 1; i <= n; i++){
        if(mx > i)
            len[i] = min(mx-i, len[2*po-i]);
        else
            len[i] = 1;
        while(str[i-len[i]] == str[i+len[i]])
            len[i]++;
        if(i+len[i] > mx){
            mx = i+len[i];
            po = i;
        }
    }
}
vector<int> a[500005];
int main(){
    int t, i, j;

    scanf("%d", &t);
    while(t--){
        ll ans = 0;
        scanf("%s", s);
        memset(c, 0, sizeof(c));
        lens = strlen(s);
        inint(s);
        manacher(lens*2+1);
        for(i = 2; i <= lens*2; i += 2) len[i/2] = len[i]/2;
        for(i = 1; i <= lens; i++) a[i].clear();
        for(i = 1; i <= lens; i++) a[i-len[i]+1].push_back(i);
        for(i = 1; i <= lens; i++){
            for(j = 0; j < a[i].size(); j++)
                updata(a[i][j], 1 , lens);
            ans += query(min(lens, i+len[i]-1)) - query(i);
        }
        printf("%lld\n", ans);
    }

    return 0;
}
上一篇:Palindrome POJ-1159


下一篇:[USACO07OPEN]便宜的回文Cheapest Palindrome