HDU6230-Palindrome

本文介绍了一种算法,用于找出给定字符串中所有符合特定条件的一弦回文子串数量。该条件涉及子串需由两个回文串组成,通过Manacher算法和主席树实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Palindrome

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


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$.
 

Source
 

Recommend
jiangzijing2015
 

题意:给你一个字符串,问其中有多少个子串符合题目中的要求
解题思路:观察可以发现,符合题目要求的子串就是两个回文串构成的,可以先通过Manacher算法求出每个位置的回文半径,并且因为回文串必须是奇数长度的,所以可以不需要添加字符。然后就是要求有多少对i和j,它们的回文半径是可以互相覆盖的到对方的即可,这个可以通过主席树来解决


#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>

using namespace std;

const int INF=0x3f3f3f3f;
#define LL long long
const int maxn=5e5+10;
char ch[maxn];
int p[maxn],len,tot;
int s[maxn],L[maxn*40],R[maxn*40];
LL sum[maxn*40];

void update(int &now,int pre,int l,int r,int p)
{
    now=++tot,L[now]=L[pre],R[now]=R[pre],sum[now]=sum[pre]+1;
    if(l==r) {L[now]=R[now]=0;return ;}
    int mid=(l+r)>>1;
    if(p<=mid) update(L[now],L[pre],l,mid,p);
    else update(R[now],R[pre],mid+1,r,p);
}

LL query(int u,int v,int l,int r,int p)
{
    if(l>=p) return sum[v]-sum[u];
    int mid=(l+r)>>1;
    LL ans=0;
    if(p<=mid) ans+=query(L[u],L[v],l,mid,p);
    ans+=query(R[u],R[v],mid+1,r,p);
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",ch+1);
        len=strlen(ch+1);
        ch[0]='#';
        memset(p,0,sizeof p);
        memset(s,0,sizeof s);
        int id=0,ma=0;
        LL ans=0;
        tot=0;
        for(int i=1;i<=len;i++)
        {
            p[i]=ma>i?min(p[id*2-i],ma-i):1;
            while(ch[i+p[i]]==ch[i-p[i]]) p[i]++;
            if(i+p[i]>ma)
            {
                ma=i+p[i];
                id=i;
            }
        }
        s[0]=0,sum[0]=0;
        for(int i=1;i<=len;i++)
        {
            if(p[i]!=1) ans+=1LL*query(s[i-p[i]],s[i-1],1,len,i);
            update(s[i],s[i-1],1,len,i+p[i]-1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值