zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    有趣的网抑云
    [扩展阅读] timeit 模块详解(准确测量小段代码的执行时间)
    第044讲:魔法方法:简单定制
    第043讲:魔法方法:算术运算2
    第042讲:魔法方法:算术运算1
    第041讲:魔法方法:构造和析构
    吴恩达深度学习 第一课第四周课后编程作业 assignment4_2
    吴恩达深度学习 第一课第四周课后编程作业 assignment4_1
    第040讲:类和对象:一些相关的BIF
    [扩展阅读] property 的详细使用方法
  • 原文地址:https://www.cnblogs.com/zxhl/p/7629204.html
Copyright © 2011-2022 走看看