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

2011
Multi-University Training Contest 11 - Host by UESTC

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);
    }
}
时间: 2024-10-06 02:38:07

hdu 3948 The Number of Palindromes的相关文章

HDOJ 3948 The Number of Palindromes 后缀数组

后缀数组求有多少个不同的回文串 The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1976    Accepted Submission(s): 690 Problem Description Now, you are given a string S. We want to kno

HDOJ 3948 The Number of Palindromes 回文串自动机

看上去像是回文串自动机的模板题,就来了一发 The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1992    Accepted Submission(s): 694 Problem Description Now, you are given a string S. We want

【HDOJ】3948 The Number of Palindromes

后缀数组求不重复回文子串数目.注意dp数组. 1 /* 3948 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <

hdu 3948 后缀数组

The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2465    Accepted Submission(s): 841 Problem Description Now, you are given a string S. We want to know how many distin

HDU 4937 Lucky Number 搜索

题意: 给你一个数,求在多少种不同的进制下这个数每一位都是3.4.5.6中的一个. 思路: 搜索.枚举这个数在任意进制下的表示,判断是否合法.当数字只有3.4.5.6时,必定有无穷种. 因为数字太大,所以直接枚举必定会超时. 下面有两种剪枝的方法: 1. 先枚举最后一位的情况. 假设数字n在base进制下表示为 a[n]...a[0],即 n = a[0] + a[1]*base^1 + ... + a[n]*base^n. 则 n - a[0] = a[1]*base^1 + ... + a[

hdu 4937 Lucky Number ( 进制转换+枚举 )

题意: 有一个数n,问有多少个进制x(基数)使得n转换为x进制后的数字中只有3.4.5.6四个数. 算法: 对于只有一位数的情况,显然3.4.5.6都应该输出-1. 如果有2位数,假设这2位中高位为a,低位为b,进制为base,则 n = a * base + b,解一元一次方程即可. 如果有3位数,假设这3为从高到低分别为a.b.c,进制为base,则 n = a * base * base + b * base + c,即一元二次方程即可. 如果位数>= 4,可以暴力枚举进制数.base>

hdu 2665 Kth number(划分树)

Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4602 Accepted Submission(s): 1468 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first l

hdu 3006 The Number of set(思维+壮压DP)

The Number of set Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1056    Accepted Submission(s): 655 Problem Description Given you n sets.All positive integers in sets are not less than 1 and

hdu 5787 K-wolf Number 数位dp

数位DP 神模板 详解 为了方便自己参看,我把代码复制过来吧 // pos = 当前处理的位置(一般从高位到低位) // pre = 上一个位的数字(更高的那一位) // status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回, // 给计数器+1. // limit = 是否受限,也即当前处理这位能否随便取值.如567,当前处理6这位, // 如果前面取的是4,则当前这位可以取0-9.如果前面取的5,那么当前 // 这位就不能随便取,不然会超出这个数的范围,所以如果前面取