news 2026/3/7 13:38:44

信奥赛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/3/6 21:05:58

如何判断自动化测试的时机?

判断自动化测试的时机时&#xff0c;可以考虑以下因素&#xff1a; 1、软件稳定性评估&#xff1a; 确定软件的开发阶段&#xff0c;如果软件还在快速迭代和开发中&#xff0c;可能变动频繁&#xff0c;不适合引入自动化测试。 分析软件的功能和接口是否已经相对稳定&#xf…

作者头像 李华
网站建设 2026/2/28 20:08:41

废品回收小程序开发运营全解析:技术架构+落地逻辑+合规防控

废品回收小程序凭借“本地化调度便捷下单合规备案”的核心逻辑&#xff0c;成为再生资源数字化的关键载体&#xff0c;但超60%的项目因智能调度低效、称重数据错乱、合规备案缺失、跨场景适配差陷入困境。本文从开发者视角&#xff0c;拆解废品回收小程序的核心技术架构、关键功…

作者头像 李华
网站建设 2026/3/7 11:43:09

基于Qwen2.5-7B的离线对话实现|附完整代码示例

基于Qwen2.5-7B的离线对话实现&#xff5c;附完整代码示例 一、引言&#xff1a;为何选择Qwen2.5-7B进行离线对话&#xff1f; 在当前大模型应用快速落地的背景下&#xff0c;离线推理正成为企业级AI服务的重要部署方式。相比在线API调用&#xff0c;离线部署不仅能显著降低长…

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

如何用Ollama运行Qwen2.5-7B?一文搞定本地大模型部署

如何用Ollama运行Qwen2.5-7B&#xff1f;一文搞定本地大模型部署 在AI技术飞速发展的今天&#xff0c;越来越多开发者和爱好者希望将大语言模型&#xff08;LLM&#xff09;部署到本地环境中&#xff0c;用于实验、开发或私有化应用。然而&#xff0c;复杂的依赖配置、硬件适配…

作者头像 李华