news 2026/4/19 15:21:08

信奥赛C++提高组csp-s之哈希

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
信奥赛C++提高组csp-s之哈希

信奥赛C++提高组csp-s之哈希

1. 什么是哈希

哈希(Hash)是将任意长度的输入通过哈希函数映射为固定长度的输出(哈希值)的过程。在字符串哈希中,我们将字符串转换为一个整数,以便:

  • 快速比较字符串是否相等
  • 快速计算子串的哈希值
  • 支持字符串的快速匹配和查找

哈希的特点:

  1. 确定性:相同字符串总是产生相同的哈希值
  2. 高效性:计算速度快
  3. 冲突可能性:不同字符串可能产生相同哈希值(哈希碰撞)
2. 如何构造字符串哈希
2.1 基本思想

将字符串看作一个P进制数,每个字符对应一个数字(通常是ASCII码),然后对一个大数M取模。

2.2 公式推导

对于一个长度为n的字符串s,我们可以将其视为P进制数:

hash(s) = (s[0] * P^(n-1) + s[1] * P^(n-2) + ... + s[n-1]) mod M
2.3 常用的参数选择
  • P(进制基数):通常选择质数,如131, 13331等
  • M(模数):选择大质数,如1e9+7, 1e9+9,或者使用自然溢出(2^64)
2.4 基础实现
#include<bits/stdc++.h>usingnamespacestd;typedefunsignedlonglongULL;// 利用自然溢出作为模数constintN=100010;constULL P=131;// 经验值,131或13331// 计算字符串的哈希值ULLcomputeHash(conststring&s){ULL h=0;for(charc:s){h=h*P+c;// 利用unsigned long long自然溢出}returnh;}intmain(){string s="hello";ULL hashValue=computeHash(s);cout<<"字符串 '"<<s<<"' 的哈希值: "<<hashValue<<endl;return0;}
3. 滚动哈希优化(前缀哈希)
3.1 为什么需要滚动哈希?

直接计算每个子串的哈希值需要O(n)时间,通过预处理前缀哈希,我们可以在O(1)时间内计算任意子串的哈希值。

3.2 实现步骤
  1. 预处理前缀哈希数组h
  2. 预处理P的幂次数组p
  3. 通过公式计算任意子串哈希值

案例研究(子串判重)

题目描述

给定一个含有 26 个小写英文字母的字符串。有 n 次询问,每次给出 2个区间,请问这两个区间里的子字符串是否一样?

输入

第一行输入一个非空字符串 s 。

第二行一个数字 n,表示 n次询问。

接下来 n行,每行四个数字 l1,r1,l2,r2,分别表示此次询问的两个区间,注意字符串的位置从 1开始编号。

数据范围:

1 ≤ n , l1 , r1 , l2 , r2 ≤10 6 10^6106

输出

对于每次询问,输出一行表示结果。

如果两个子串完全一样,输出YES,否则输出NO

样例输入

abcdebcd 3 2 3 6 7 1 3 4 6 2 5 2 5

样例输出

YES NO YES

思路分析

这个问题需要通过字符串哈希技术来实现O(1)时间复杂度的子串比较。核心思想是将字符串转换为数值(哈希值),通过比较哈希值来判断子串是否相等。

关键技术点
  1. 字符串哈希原理

    • 将字符串看作一个P进制的数(P通常取131或13331)
    • 预处理每个前缀的哈希值和P的幂次
    • 通过前缀哈希值的组合可以在O(1)时间内计算任意子串的哈希值
  2. 哈希公式

    • 前缀哈希:h[i] = h[i-1] * P + s[i]
    • 子串哈希:hash(l,r) = h[r] - h[l-1] * p[r-l+1]
  3. 避免哈希冲突

    • 使用unsigned long long自然溢出(自动对2 64 2^{64}264取模)
    • 也可以使用双哈希或更大的质数模数

代码实现

#include<bits/stdc++.h>usingnamespacestd;typedefunsignedlonglongULL;// 使用unsigned long long自然溢出作为哈希值constintN=1e6+10;// 最大字符串长度+10constULL P=131;// 哈希基数,通常取131或13331ULL h[N];// h[i]存储前i个字符的哈希值ULL p[N];// p[i]存储P的i次幂,用于快速计算子串哈希chars[N];// 存储输入字符串(从索引1开始)intn;// 询问次数/** * 计算子串[l, r]的哈希值 * 公式:hash(l, r) = h[r] - h[l-1] * p[r-l+1] */ULLgetHash(intl,intr){returnh[r]-h[l-1]*p[r-l+1];}intmain(){// 读入字符串,从索引1开始存储scanf("%s",s+1);// 初始化p[0] = 1(P^0 = 1)p[0]=1;// 获取字符串长度intlen=strlen(s+1);// 预处理哈希数组和幂次数组for(inti=1;i<=len;i++){// p[i] = P^i,用于后续计算p[i]=p[i-1]*P;// h[i] = h[i-1] * P + s[i]的编码值// s[i]-'a'+1:将字符a-z映射为1-26h[i]=h[i-1]*P+(s[i]-'a'+1);}// 读入询问次数cin>>n;// 处理每个询问while(n--){intl1,r1,l2,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);// 比较两个子串的哈希值if(getHash(l1,r1)==getHash(l2,r2)){printf("YES\n");}else{printf("NO\n");}}return0;}

功能分析

1.时间复杂度
  • 预处理:O(n),n为字符串长度
  • 每次查询:O(1)
  • 总复杂度:O(n + q),其中q为查询次数
2.空间复杂度
  • O(n),用于存储前缀哈希值和幂次数组
3.算法正确性保证
  • 哈希冲突概率:使用自然溢出(对2^64取模)和合适的基数P,冲突概率极低
  • 数值范围unsigned long long范围[0, 2^64-1],足够容纳哈希值
4.边界情况处理
  • 字符串长度为1
  • 查询区间为整个字符串
  • 多个相同查询
  • 区间完全重合(如样例中的2 5 2 5)
5.优化思考
  • 可以添加长度检查快速排除不等长的情况
  • 对于大数据集,可以使用双哈希进一步降低冲突概率
// 使用两个不同的P和MOD,降低哈希冲突概率constintP1=131,P2=13331;constintMOD1=1e9+7,MOD2=1e9+9;

更多系列知识,请查看专栏:《信奥赛C++提高组csp-s知识详解及案例实践》:
https://blog.csdn.net/weixin_66461496/category_13113932.html

各种学习资料,助力大家一站式学习和提升!!!

#include<bits/stdc++.h>usingnamespacestd;intmain(){cout<<"########## 一站式掌握信奥赛知识! ##########";cout<<"############# 冲刺信奥赛拿奖! #############";cout<<"###### 课程购买后永久学习,不受限制! ######";return0;}
  • 一、CSP信奥赛C++通关学习视频课:
    • C++语法基础
    • C++语法进阶
    • C++算法
    • C++数据结构
    • CSP信奥赛数学
    • CSP信奥赛STL
  • 二、CSP信奥赛C++竞赛拿奖视频课:
    • 信奥赛csp-j初赛高频考点解析
    • CSP信奥赛C++复赛集训课(12大高频考点专题集训)
  • 三、csp高频考点知识详解及案例实践:
    • CSP信奥赛C++之动态规划
    • CSP信奥赛C++之标准模板库STL
    • 信奥赛C++提高组csp-s知识详解及案例实践
  • 四、考级、竞赛刷题题单及题解:
    • GESP C++考级真题题解
    • CSP信奥赛C++初赛及复赛高频考点真题解析
    • CSP信奥赛C++一等奖通关刷题题单及题解

详细内容:

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转


2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html

4、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

· 文末祝福 ·

#include<bits/stdc++.h>usingnamespacestd;intmain(){cout<<"跟着王老师一起学习信奥赛C++";cout<<" 成就更好的自己! ";cout<<" csp信奥赛一等奖属于你! ";return0;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 8:04:47

从零搭建Qwen2.5-7B推理服务|vLLM加速全步骤解析

从零搭建Qwen2.5-7B推理服务&#xff5c;vLLM加速全步骤解析 随着大语言模型能力的持续进化&#xff0c;Qwen2.5系列在知识广度、编程与数学推理、长文本生成及多语言支持等方面实现了显著跃升。其中&#xff0c;Qwen2.5-7B-Instruct作为70亿参数级别的指令微调模型&#xff0…

作者头像 李华
网站建设 2026/4/19 15:21:07

Rembg模型解释:显著性检测原理剖析

Rembg模型解释&#xff1a;显著性检测原理剖析 1. 智能万能抠图 - Rembg 在图像处理与内容创作领域&#xff0c;自动去背景&#xff08;Image Matting / Background Removal&#xff09;是一项高频且关键的需求。无论是电商商品图精修、社交媒体头像设计&#xff0c;还是AI生…

作者头像 李华
网站建设 2026/4/17 22:47:28

2026年入门网络安全工程师要学习哪些内容

大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网络安全工程师需要学什么?知了堂小编总结出以下要点。 网络安全工程师是一个概称&#xff0c;学习的东西很多&…

作者头像 李华
网站建设 2026/4/18 14:41:07

性能最佳实践

最佳实践&#xff08;Best Practices&#xff09;是指在特定领域或特定任务中&#xff0c;被广泛认可并被认为是最有效、最高效、最安全的方法或做法。它们是基于经验、实践和研究得出的&#xff0c;旨在提供一种可靠的指导&#xff0c;以帮助人们在特定情境下取得良好的结果。…

作者头像 李华
网站建设 2026/4/17 17:28:58

Rembg高精度抠图保姆级教程:电商商品去背景实战

Rembg高精度抠图保姆级教程&#xff1a;电商商品去背景实战 1. 引言&#xff1a;智能万能抠图 - Rembg 在电商、广告设计和内容创作领域&#xff0c;高质量的图像去背景处理是提升视觉表现力的关键环节。传统手动抠图耗时耗力&#xff0c;而自动化工具有时难以应对复杂边缘&a…

作者头像 李华
网站建设 2026/4/19 14:41:31

H5交互设计:从策划到上线的实用方法论与避坑要点

做了7年H5设计&#xff0c;见过太多“为炫酷而炫酷”的翻车案例——比如加了5秒开场动画&#xff0c;用户还没看到核心信息就划走&#xff1b;比如把报名按钮藏在第三屏&#xff0c;转化率低到1%&#xff1b;再比如安卓机上字体乱码&#xff0c;iOS上动画卡顿。其实H5的核心从来…

作者头像 李华