Hihocoder #1602 : 本质不同的回文子串的数量 manacher + BKDRhash

#1602 : 本质不同的回文子串的数量

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

给定一个字符串S,请统计S的所有子串中,有多少个本质不同的回文字符串?

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

输入

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

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

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

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

输出

回文子串的数量

样例输入
abbab
样例输出
5
题解:
  跑manacher的时候 hash标记即可
#include <bits/stdc++.h>
inline long long read(){long long x=0,f=1;char ch=getchar();while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}return x*f;}
using namespace std;

const long long INF = 1e14;
const int N = 1e6 + 7;

unsigned long long P = 10000019ULL;
unsigned long long sqr[N],has[N];

//BKDRHash,最优的字符串hash算法。hash一开始是等于0的
const int seed = 13131; // 31 131 1313 13131 131313 etc..
const int maxn = 2000000+10;
char str[maxn];
unsigned long long sumHash[maxn]; //前缀hash值
const int MOD = 2000007;
struct StringHash
{
    int first[MOD+2],num;
    unsigned long long EdgeNum[maxn]; // 表明第i条边放的数字(就是sumHash那个数字)
    int next[maxn],close[maxn]; //close[i]表示与第i条边所放权值相同的开始的最大位置
    //就比如baba,现在枚举长度是2,开始的时候ba,close[1] = 1;表明"ba"开始最大位置是从1开始
    //然后枚举到下一个ba的时候,close[1]就要变成3了,开始位置从3开始了
    void init ()
    {
        num = 0; memset (first,0,sizeof first);
        return ;
    }
    int insert (unsigned long long val,int id) //id是用来改变close[]的
    {
        int u = val % MOD;
        for (int i = first[u]; i ; i = next[i]) //存在边不代表出现过,出现过要用val判断,val才是唯一的,边还是压缩后(%MOD)的呢
        {
            if (val == EdgeNum[i]) //出现过了
            {
                int t = close[i]; close[i] = id;//更新最大位置
                return t;
            }
        }
        ++num; //没出现过的话,就加入图吧
        EdgeNum[num] = val; // 这个才是精确的
        close[num] = id;
        next[num] = first[u];
        first[u] = num;
        return 0;//没出现过
    }
}H;

char a[N];
int ans = 0;
map<unsigned long long, int> mp;
void gao(int i,int j) {
    unsigned long long now = has[j] - has[i-1] * sqr[j-i+1];
    if(!H.insert(now,1)) ++ans,mp[now]++;
}
int r[N];
int main() {
    scanf("%s",a+1);
    int n = strlen(a+1);
    sqr[0] = 1;for(int i = 1; i <= n; ++i) sqr[i] = sqr[i-1] * P;
    for(int i = 1; i <= n; ++i) has[i] = has[i-1] * P + a[i];
    int x = 0, p = 0;
    for(int i = 1; i <= n; ++i) {
        int j = 0;
        gao(i,i);
        if(p > i) j = min(r[2*x-i],p-i);
        while(i + j + 1 <= n&& a[i+j+1] == a[i-j-1])
        {
            gao(i-j-1,i+j+1);
            j++;
        }
        r[i] = j;
        if(i+j > p) {
            p = i + j;
            x = i;
        }
    }
    H.init();
    x = 0,p = 0;
    for(int i = 2; i <= n; ++i) {
        int j = 0;
        if(p > i) j = min(r[2*x-i],p-i+1);
        while(i+j<=n && a[i+j] == a[i-j-1]) {
            gao(i-j-1,i+j);
            ++j;
        }
        r[i] = j;
        if(i+j-1 > p) {
            p = i+j-1;
            x = i;
        }
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:http://www.cnblogs.com/zxhl/p/7629204.html

时间: 2024-08-26 01:08:42

Hihocoder #1602 : 本质不同的回文子串的数量 manacher + BKDRhash的相关文章

647. Palindromic Substrings 回文子串的数量

Given a string, your task is to count how many palindromic substrings in this string. The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters. Example 1: Input: "abc" Ou

hdu5371 最长回文子串变形(Manacher算法)

http://acm.hdu.edu.cn/showproblem.php? pid=5371 Problem Description Hotaru Ichijou recently is addicated to math problems. Now she is playing with N-sequence. Let's define N-sequence, which is composed with three parts and satisfied with the followin

51nod 1089 最长回文子串 V2(Manacher算法)

1089 最长回文子串 V2(Manacher算法) 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 回文串是指aba.abba.cccbccc.aaaa这种左右对称的字符串. 输入一个字符串Str,输出Str里最长回文子串的长度. Input 输入Str(Str的长度 <= 100000) Output 输出最长回文子串的长度L. Input示例 daabaac Output示例 5 #include <iostream> #include

【回文字符串】 最长回文子串O(N) Manacher算法

原理讲的清晰:Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串 注意: ①动态生命P[]和newStr数组后,不要忘记delete[] //其实这是基本的编码习惯 ②最终返回结果是P[i]-1 下面是自己写的Manacher函数 int manacher(char *src){ int srcLen=strlen(src); int len=2*srcLen+2; char *newStr=new char[len];//还是+3??要不要给\0留个位置??不用 i

【51NOD-0】1089 最长回文子串 V2(Manacher算法)

[算法]回文树 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=100010; struct trees{int len,fail,t[260];}t[maxn]; char s[maxn]; int n,len,l,sz,ans; int getfail(int x) { while(s[len-t[x].len-1]!=s[len])

WHU 583 Palindrome ( 回文自动机 &amp;&amp; 本质不同的回文串的个数 )

题目链接 题意 : 给你一个串.要你将其划分成两个串.使得左边的串的本质不同回文子串的个数是右边串的两倍.对于每一个这样子的划分.其对答案的贡献就是左边串的长度.现在要你找出所有这样子的划分.并将贡献乘起来.答案 mod 1e9+7 分析 : 从左到右跑一边回文自动机.对于每个前缀 能够得出其有多少个本质不同的回文子串 本质不同的回文子串的个数实际上就是自动机节点数 - 2 那么跑一遍前缀之后我们能得到所有可作为左边部分串的本质不同回文子串的个数 因为是回文串.所以我们倒着跑一遍.就同样能得到作

51nod1089最长回文子串V2

1089 最长回文子串 V2(Manacher算法) 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 回文串是指aba.abba.cccbccc.aaaa这种左右对称的字符串. 输入一个字符串Str,输出Str里最长回文子串的长度. Input 输入Str(Str的长度 <= 100000) Output 输出最长回文子串的长度L. Input示例 daabaac Output示例 5 看到这道题才特意去看了下Manacher算法:参考博客:http://blog.

1089 最长回文子串

1089 最长回文子串 V2(Manacher算法) 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 回文串是指aba.abba.cccbccc.aaaa这种左右对称的字符串. 输入一个字符串Str,输出Str里最长回文子串的长度. Input 输入Str(Str的长度 <= 100000) Output 输出最长回文子串的长度L. Input示例 daabaac Output示例 5 马拉车算法的模板题也算是又进一步理解马拉车算法了. 1 //马拉车算法 2 #i

最长回文子串(转自:hihoCoder)

#1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:"小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?" 小Ho奇怪的问道:"什么叫做最长回文子串呢?" 小Hi回答道:"一个字符串中连续的一