HDU6230 Palindrome(Manachar + 树状数组)

                                    Palindrome

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1267    Accepted Submission(s): 469


 

Problem Description

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[2ni]=S[2n+i−2](1≤in).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, $abab$ and $abcbabc$.

 

在做这道题时,刚刚复习了Manachar,好久没有写Manachar,所以有很多Bug。

题意中定义一个字符串,S[i]=S[2n−i]=S[2n+i−2](1≤i≤n) ,根据观察可以知道题目中要求的回文串大致为 

______ i ____ j ______  分别以 i j 为中心的两个回文串。所以首先用Manachar预处理字符串,获得以每个字符为中心的回文串长度,即p[i] 为以i为中心的回文串的半径长度。

题意中定义的字符串有三个要求:

i  < j

p[i] + i >= j

j  <= i + p[j]

将 第三个式子变形为 j - p[j] <= i ,

所以我们可以每次把 满足条件j - p[j] <= i的 j 放入树状数组中,然后每次求在 ( i  , i+p[i] ] 范围内的j有多少

/*************************************************************************
	> File Name: hdu6230.cpp
	> Author: ccdxc
	> Created Time: 2019年04月17日 星期三 13时43分07秒
 ************************************************************************/

#include<bits/stdc++.h>
#define ll long long 
#define pb push_back
using namespace std;
const int INF = 0x3f3f3f3f;
const int Maxn = 5e5 + 10;
string str;
int T ,bit[Maxn] ,len , n;
int lowbit(int x){
    return x & -x;
}
void add(int i , int x){
    while(i <= n){
        bit[i] += x;
        i += lowbit(i);
    }
}
int sum(int i){
    int ans = 0;
    while(i > 0){
        ans += bit[i];
        i -= lowbit(i);
    }
    return ans;
}
vector<int>mp[Maxn];
int main(){
    cin >> T;
    while(T--){
        for(int i = 0;i <= n ;i++) mp[i].clear() , bit[i] = 0;
        cin >> str;
        //Manachar预处理字符串
        string s = "$#";
        n = str.length();
        for(int i = 0;i < n;i++) s += str[i] , s += "#";
        len = s.length();
        vector<int>p(len , 0);
        int mx = 0 , id = 0;
        for(int i = 1;i < len ;i++){
            p[i] = mx > i? min(mx - i , p[id * 2 - i]):1;
            while(s[i + p[i]] == s[i -p[i]]) p[i]++;
            if(p[i] + i > mx){
                mx = p[i] + i;
                id= i;
            }
        }
        for(int i = 2;i < len;i += 2){
            //cout <<p[i] <<" ";
            p[i / 2] = p[i] / 2 - 1;
            mp[(i/2) - p[i / 2]].pb(i / 2);
        }
        //cout << endl;
        ll ans = 0;
        for(int i = 1;i <= n ; i++){
            for(int j = 0;j < mp[i].size();j++){
                add(mp[i][j] ,1);
            }
            ans += (ll)sum(min(n , i + p[i])) - (ll)sum(i);
        }
        cout << ans <<endl;
    }
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值