HDU 6230 Palindrome

20 篇文章 0 订阅

题目连接:HDU6230

Palindrome

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


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..3n2](n2) is one-and-half palindromic if and only if it satisfies S[i]=S[2ni]=S[2n+i2](1in).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$.
 

题意:定义一个半回文串,问一个长串里有多少一个半回文串。

题目分析:首先用manacher处理字符串,获得每个字母为中心的回文串半径。

之后判断一个子串是否是一个半回文串:

_______i______j______若是一个半回文串的话需要满足以下3个条件:

i<j

j-i<=p[i]

j-i<=p[j]

对不等式进行移项,获得以下2个不等式:

i<j<=i+p[i]

i>=j-p[j]

问题转化为:对每个i,求在i到i+p[i]范围内有多少个j满足i>=j-p[j]。

预处理j-p[j],存在vector v[i]中,v[i]数组存的是满足j-p[j]==i的j的位置。

这样从前到后扫一遍i,每次使用树状数组update v[I]中的位置,然后求和统计sum(i+p[i])-sum(i)即可。

注意答案会比较大,需要用long long来存。

代码:

//
//  main.cpp
//  HDU 6230 Palindrome
//
//  Created by teddywang on 2017/12/12.
//  Copyright © 2017年 teddywang. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int T;
char s[1011111];
int p[1011111];
int c[511111];
vector<int> v[511111];
char Ma[511111*2];
int Mp[511111*2];
int Manacher(char s[],int len)
{
    int l = 0;
    Ma[l++] = '$';
    Ma[l++] = '#';
    for(int i = 0; i<len; i++)
    {
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l] = 0;
    int mx = 0, id = 0;
    for(int i = 0; i<l; i++)
    {
        Mp[i] = mx>i ? min(Mp[2*id-i],mx-i) : 1;
        while(i-Mp[i]>=0 && Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;
        if(i+Mp[i]>mx)
        {
            mx=i+Mp[i];
            id=i;
        }
    }
    return l;
}

int lowbit(int x)
{
    return x&(-x);
}

void update(int x,int num,int n)
{
    while(x<=n)
    {
        c[x]+=num;
        x+=lowbit(x);
    }
}

int getsum(int x)
{
    int s=0;
    while(x>0)
    {
        s+=c[x];
        x-=lowbit(x);
    }
    return s;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(c,0,sizeof(c));
        scanf("%s",s);
        int slen = strlen(s);
        for(int i = 0; i<=slen; i++) v[i].clear();
        int len = Manacher(s,slen);
        int k=1;
        for(int i=2;i<len;i+=2)
        {
            p[k]=Mp[i]/2-1;
            v[k-p[k]].push_back(k);
            k++;
        }
        len=strlen(s);
        long long ans=0;
        for(int i=1;i<=len;i++)
        {
            int l=v[i].size();
            for(int j=0;j<l;j++)
            {
                    update(v[i][j],1,len);
            }
            ans+=getsum(min(i+p[i],len))-getsum(i);
        }
        printf("%lld\n",ans);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值