hdu 3948 The Number of Palindromes

The Number of Palindromes

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
http://acm.hdu.edu.cn/showproblem.php?pid=3948

Problem Description
Now, you are given a string S. We want to know how many distinct substring of S which is palindrome.
 
Input
The first line of the input contains a single integer T(T<=20), which indicates number of test cases.
Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.
 
Output
For every test case, you should output "Case #k:" first in a single line, where k indicates the case number and starts at 1. Then output the number of distinct substring of S which is palindrome.
 
Sample Input
3
aaaa
abab
abcd
 
Sample Output
Case #1: 4
Case #2: 4
Case #3: 4
 
Source
 
Recommend
xubiao   |   We have carefully selected several similar problems for you:   3946  3947  3949  3945  3944 
 
题意:统计不同回文串的个数
首先对原串跑一遍manacher算法,处理出最长回文半径
然后枚举每一个位置
从最长的回文串开始一点一点儿往里索,hash判断这个字符串是否出现过
如果出现过,那么比它更短的肯定也出现过,结束本位置的查找,到下一个位置
 
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define D1 28
#define D2 38
using namespace std;
const int MOD1=300137;
const int MOD2=17707;
const int MOD3=1e9+7;
const int MOD4=1e9+9;
char s[200011],a[100011];
int p[200011],len,l,ans;
int f1[200011],g1[200011];
int f2[200011],g2[200011];
int front1[MOD1+1],front2[MOD2+1];
int to1[300100],to2[300100];
int nxt1[300100],nxt2[300100];
int tot1,tot2;
void manacher()
{
    memset(p,0,sizeof(p));
    int pos=0,id=0,x;
    for(int i=1;i<=len;i++)
    {
        if(i<pos) x=min(p[2*id-i],pos-i);
        else x=1;
        while(s[i+x]==s[i-x])    x++;
        if(i+x>pos) { pos=i+x; id=i; }
        p[i]=x;
    }
}
int get_hash1(int l,int r)
{
    int a=f1[r];
    int b=1ll*f1[l-1]*g1[r-l+1]%MOD3;
    return (b-a+MOD3)%MOD3;
}
int get_hash2(int l,int r)
{
    int a=f2[r];
    int b=1ll*f2[l-1]*g2[r-l+1]%MOD4;
    return (b-a+MOD4)%MOD4;
}
void add1(int u,int v)
{
    to1[++tot1]=v; nxt1[tot1]=front1[u]; front1[u]=tot1;
}
void add2(int u,int v)
{
    to2[++tot2]=v; nxt2[tot2]=front2[u]; front2[u]=tot2;
}
bool find1(int u,int v)
{
    for(int i=front1[u];i;i=nxt1[i])
     if(to1[i]==v) return true;
    return false;
}        
bool find2(int u,int v)
{
    for(int i=front2[u];i;i=nxt2[i])
     if(to2[i]==v) return true;
    return false;
}
void cal(int pos,int len)
{
    for(int i=len;i>=1;i--)
    {
        int hash1=get_hash1(pos-i+1,pos+i-1);
        int hash2=get_hash2(pos-i+1,pos+i-1);
        int t1=hash1%MOD1,t2=hash2%MOD2;
        if(!(find1(t1,hash1)&&find2(t2,hash2)))
        {
            ans++;
            add1(t1,hash1);
            add2(t2,hash2);
        }
        else return;
    }
}
void pre()
{
    ans=tot1=tot2=0;
    memset(front1,0,sizeof(front1));
    memset(front2,0,sizeof(front2));
    memset(f1,0,sizeof(f1));
    memset(f2,0,sizeof(f2));
    g1[0]=1;
    for(int i=1;i<=len;i++) g1[i]=1ll*g1[i-1]*D1%MOD3;
    f1[0]=s[0];
    for(int i=1;i<=len;i++) f1[i]=(1LL*f1[i-1]*D1+s[i]-'0')%MOD3;
    g2[0]=1;
    for(int i=1;i<=len;i++) g2[i]=1ll*g2[i-1]*D2%MOD4;
    f2[0]=s[0];
    for(int i=1;i<=len;i++) f2[i]=(1LL*f2[i-1]*D2+s[i]-'0')%MOD4;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int tt=1;tt<=t;tt++)
    {
        scanf("%s",a);
        s[len=0]='!';
        l=strlen(a);
        for(int i=0;i<l;i++) 
        {
            s[++len]='#';
            s[++len]=a[i];
        }
        s[++len]='#';
        s[len+1]='&';
        pre();
        manacher();
        for(int i=1;i<=len;i++)
           cal(i,p[i]);
        printf("Case #%d: %d\n",tt,ans/2);
    }
}

 

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/6952527.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值