hihocoder#1602 : 本质不同的回文子串的数量(manacher+Hash)

版权声明:http://blog.csdn.net/Mitsuha_。 https://blog.csdn.net/Mitsuha_/article/details/82313537

时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个字符串S,请统计S的所有子串中,有多少个本质不同的回文字符串?

注意如果两个位置不同的子串满足长度相同且对应字符也都相同,则认为这两个子串本质上是相同的。

输入
一个只包含小写字母的字符串S。

对于30%的数据,S长度不超过100。

对于60%的数据,S长度不超过1000。

对于100%的数据,S长度不超过800000。

输出
回文子串的数量

样例输入
abbab
样例输出
5

思路:利用manacher求出所有子串然后插入hash表统计。

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e6+10;
const int Hashsize=2000003;
const unsigned long long p=131;
typedef long long ll;
typedef unsigned long long ull;
struct lenka
{
    int next;
    ull val;
}ed[MAX];
int head[MAX],cnt=0;
ull f[MAX],sum[MAX];
int ans=0;
void Insert(int x,int y)
{
    ull tot=sum[y]-sum[x-1]*f[y-x+1];
    for(int i=head[tot%Hashsize];i!=-1;i=ed[i].next)
    {
        if(tot==ed[i].val)return;
    }
    ans++;
    ed[cnt].next=head[tot%Hashsize];
    ed[cnt].val=tot;
    head[tot%Hashsize]=cnt++;
}
char s[MAX];
int len[MAX];
int main()
{
    scanf("%s",s+1);
    int n=strlen(s+1);
    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        f[i]=f[i-1]*p;
        sum[i]=sum[i-1]*p+s[i];
    }
    memset(head,-1,sizeof head);
    cnt=0;
    int mx=0,x=0;
    for(int i=1;i<=n;i++)
    {
        Insert(i,i);
        if(mx>i)len[i]=min(mx-i,len[2*x-i]);
        while(i+len[i]+1<=n&&s[i+len[i]+1]==s[i-len[i]-1])
        {
            Insert(i-len[i]-1,i+len[i]+1);
            len[i]++;
        }
        if(i+len[i]>mx)
        {
            mx=i+len[i];
            x=i;
        }
    }
    mx=x=0;
    memset(len,0,sizeof len);
    memset(head,-1,sizeof head);
    cnt=0;
    for(int i=2;i<=n;i++)
    {
        if(mx>i)len[i]=min(mx-i+1,len[2*x-i]);
        while(i+len[i]<=n&&s[i+len[i]]==s[i-len[i]-1])
        {
            Insert(i-len[i]-1,i+len[i]);
            len[i]++;
        }
        if(i+len[i]-1>mx)
        {
            mx=i+len[i]-1;
            x=i;
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/82313537