013(oulipo)
阅读原文时间:2023年07月11日阅读:1

题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1455

题目描述:在母串里找子串出现的次数

题目思路:与字符串的搜索有关那就立刻找到哈希

从s[1]到s[m]将从第1位到第i位的哈希值算出来

在以m-n为固定的差值定义字串长度,在找到每一个子串

属于哈希模板题

#include<bits/stdc++.h>
using namespace std;
const int b=31;//我们需要一个质数
#define N 1000001
#define ull unsigned long long
//需要一个超级大的存储,否则数字太大,如果溢出过多就会很麻烦
ull p[N],sum[N],x;
int t,ans,i,n,m;
char s1[N],s2[N];
int main(){
    p[0]=1;//(b^0=1)
    for(i=1;i<=N;++i){
        p[i]=p[i-1]*b;//先把这些次方都存起来,以后有用
    }
    scanf("%d",&t);
    while(t--){
        ans=0;
        scanf("%s%s",s1+1,s2+1);
        //s1是我们要找的子串
         //s2是母串
        n=strlen(s1+1);//长度
        m=strlen(s2+1);//长度
        sum[0]=0;//先初始化防止后面根据公式计算哈希值的时候有多余的东西
        for(i=1;i<=m;++i){
            sum[i]=sum[i-1]*b+(ull)(s2[i]-'A'+1);
        }//声明:公式H[m]=(C[1]*b^(m-1)+C[2]*b^(m-2)+...+C[m]*1)
        x=0;//同样的道理
        for(i=1;i<=n;++i){
            x=x*b+(ull)(s1[i]-'A'+1);
        }
        for(i=0;i<=m-n;++i){
            if(x==sum[i+n]-sum[i]*p[n]){
            //如果分段上的哈希值对上了
            //注:以第一个数字为将要搜索的子串的起点,一直轮班到第m-n个,可以找遍所有子串
            //(sum[i+n]-sum[i]*p[n])是计算子串哈希的公式,可以做一个H[m]和H[n]自行推导(m<n)
                ans++;//搜索数量加1
            }
        }
        printf("%d\n",ans);//输出
    }
    return 0;
}

题目总结:做好哈希一类的题我们需要考虑三个方面

一:对公式的推导

首先是基本公式 H[m]=(C[1]*b^(m-1)+C[2]*b^(m-2)+…+C[m]*1)

然后就是对子串的计算

对于C'=C[1]C[2]…C[n]

H[C']=H[k+n]-H[k]*b^n

二:对b^n的优化

直接在前面就存是最好的选择

三:比较

哈希值相同的字符串大概率相同,在一些题目中可以近似为一定相同

哈希值不同的字符串一定不同

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章