算法竞赛中的hash技巧(个人收集使用)

pb_ds库的讲解和应用举例 之前玩了玩bp_ds库,发现它的确有好用之处,却也有一些缺陷。 阅读详情

算法竞赛(xcpc)中的hash技巧

所谓哈希(hash),即把一些需要比较的信息映射为一个具体的值,做到 O ( 1 ) O(1) O(1)对比,这个信息可能是一个字符串、集合、树等等

常见的库函数hash表

在标准库实现里,每个元素的散列值是将值对一个质数取模得到的,更具体地说,是 这个列表 中的质数(g++ 6 及以前版本的编译器,因此可以通过向容器中插入这些模数的倍数来达到制造大量哈希冲突的目的。

std::unordered_map<Key, Value>

  • 复杂度平均O(1),最坏能由于碰撞被卡到O(n)
  • 适用于:频率计数,map映射,状态记录
  • 注意其默认不支持pair<int, int>作为键。
缺点
  • 默认哈希函数容易被卡
  • 容易被卡到O(n),即被卡常
unordered_map<int, int> cnt;
cnt[x]++;  // 对 x 计数
自定义哈希函数

为了避免被卡常,我们可以自定义哈希函数,使用自定义哈希函数可以有效避免构造hack产生的大量哈希冲突。

要想使用自定义哈希函数,需要定义一个结构体,并在结构体中重载 () 运算符,像这样:

struct my_hash {
  static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }

  size_t operator()(uint64_t x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x + FIXED_RANDOM);
  }

  // 针对 std::pair<int, int> 作为主键类型的哈希函数
  size_t operator()(pair<uint64_t, uint64_t> x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x.first + FIXED_RANDOM) ^
           (splitmix64(x.second + FIXED_RANDOM) >> 1);
  }
};
// unordered_map<int, int, my_hash> my_map; 
//unordered_map<pair<int, int>, int, my_hash> my_pair_map;

std::map

  • 基于红黑树实现,稳定O(logn)
  • 排序容器
  • 比unordered_map慢,但不会被卡

std::unordered_set

  • 存储不重复的集合元素,支持快速判重
  • insert、count、erase均摊O(1)

__gnu_pbds::gp_hash_table<Key, Value, Hash>

  • 来自GNU PBDS,是C++ STL的增强版
  • 用来替代unordered_map,抗卡常能力很强
  • 自带高质量哈希函数
  • 但在主流竞赛的支持性未知
#include <ext/pb_ds/assoc_container.hpp>

__gnu_pbds::gp_hash_table<u64, int> mp;

实测在2025杭电多校,性质不同的数字

使用gp_hash_table替代unordered_map快了600ms

在这里插入图片描述

字符串hash(rolling hash)

这里参考了cup-pyy:一种科学的字符串哈希方法。
字符串hash本质上是把两个子串看成两个B进制下的数,然后比较两个数是否相等,但是因为数字本身会非常大,我们很难直接比较,所以我们把数字对一个大数取模后再进行比较.

常见的错误hash

  • 1e9级别的单模hash:不特意去卡都很容易出锅,根据生日攻击理论,比较次数达到 O ( s q r t ( 1 0 9 ) ) O(sqrt(10^9)) O(sqrt(109))就有50%的概率crash。
  • 非质数模数:比如最常见的自然溢出,即对 2 64 2^{64} 264取模,这种会被Thue-Morse序列卡掉
  • 固定模数的hash:在其他比赛和线下赛基本没问题,但是在一些具有Hack机制的比赛(Codeforces),这可以通过一些数学方法计算出冲突情况的解来卡掉hash。
  • 效率问题:在一些非期望解的情况下,可能出现单模wa,多模tle的情况,这是因为取模操作的常数巨大。

为了避免被卡的问题,我们选取mod= 2 61 − 1 2^{61}-1 261−1,随机底数的hash。我们有一些方法优化在这个模数下的加法和乘法。

using u64 = unsigned long long;
constexpr int N = 2e5 + 10;
constexpr u64 mod = (1ull << 61) - 1;
u64 power[N];
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<u64> dist(mod / 2, mod - 1);
const u64 base = dist(rng);
u64 add(u64 a, u64 b) {
    a += b;
    if(a >= mod) a -= mod;
    return a;
}
u64 mul(u64 a, u64 b) {
    __uint128_t c = __uint128_t(a) * b;
    return add(c >> 61, c & mod);
}
//合并两个字符串hash
u64 merge(u64 h1, u64 h2, int len2) {
    return add(mul(h1, power[len2]), h2);
}
//初始化
void init() {
    power[0] = 1;
    for(int i = 1; i < N; ++i) {
        power[i] = mul(power[i - 1], base);
    }
}
vector<u64> build(const string &s) {
    int sz = s.size();;
    vector<u64> hashed(sz + 1);
    for(int i = 0; i < sz; ++i) {
        hashed[i + 1] = add(mul(hashed[i], base), s[i]);
    }
    return hashed;
}

template<typename T>
vector<u64> build(const vector<T> &s) {
    int sz = s.size();
    vector<u64> hashed(sz + 1);
    for(int i = 0; i < sz; ++i) {
        hashed[i + 1] = add(mul(hashed[i], base), s[i]);
    }
    return hashed;
}
// 查询 l, r的子串hash
u64 query(const vector<u64> &s, int l, int r) {
    return add(s[r], mod - mul(s[l - 1], power[r - l + 1]));
}
// 查询两个字符串的最长lcp
int lcp(const vector<u64> &a, int l1, int r1, const vector<u64> &b, int l2, int r2) {
    int len = min(r1 - l1 + 1, r2 - l2 + 1);
    int l = 0, r = len;
    int res = 0;
    while(l <= r) {
        int mid = (l + r) / 2;
        if(query(a, l1, l1 + mid - 1) == query(b, l2, l2 + mid - 1)) {
            res = mid;
            l = mid + 1;
        } else r = mid - 1;
    }
    return res;
}

组合哈希

线性合并哈希(有序)

适用于:数组、字符串、tuple、pair等

使用类似于字符串哈希的方法。

异或组合哈希 (无序)

适用于无序集合、多重集合。

由于异或的特殊性(两个相同数异或为0),异或哈希具有灵活的应用,常见的可以判断在一个集合中一个数的出现次数是奇数还是偶数。

如2025牛客多校Equal、2025杭电多校性质不同的数字。

pair/tuple哈希

对于pair和tuple我们使用自定义unorder_map的hash函数来进行hash。

struct my_hash {
  static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }

  size_t operator()(uint64_t x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x + FIXED_RANDOM);
  }

  // 针对 std::pair<int, int> 作为主键类型的哈希函数
  size_t operator()(pair<uint64_t, uint64_t> x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x.first + FIXED_RANDOM) ^
           (splitmix64(x.second + FIXED_RANDOM) >> 1);
  }
};
GNU C++ PBDS库深度解析:哈希表、可并堆与秩序统计树实战指南 在C++高性能编程和算法竞赛中,数据结构的选择直接影响程序效率。标准模板库(STL)提供了基础容器,但在极端性能场景下可能力不从心。GNU C++的Policy-Based Data Structures(PBDS)库通过策略化设计,允许开发者定制高性能数据结构。其核心原理是将哈希函数、节点更新等行为抽象为可插拔策略,从而在缓存局部性和算法效率上实现优化。技术价值在于提供了超越STL的性能和功能,如O(1)摊还时间复杂度的堆合并、O(log n)的秩序统计查询。应用场景包括高频查找系统、动态中位数维护、区间 阅读详情

相关推荐

Argon2:现代密码哈希算法的首选

Argon2 是一种**专门设计用于抵抗高性能硬件攻击(如 GPU、FPGA 和 ASIC)**的密码哈希算法。与传统算法相比,Argon2 在内存使用、计算复杂度以及并行度方面都有极大的灵活性和优势。

A_Lonely_Smile的博客 3337

__gnu_pbds//平板电视 使用方法(部分)

__gnu_pbds//平板电视 使用方法(部分)

m0_73332554的博客 264

字符串哈希算法简单入门学习

字符串哈希算法 字符串哈希,最著名的就是BKDRHash,也就是将字符串变成数值,并且最后变成的数值是一个P进制的数(一班取131或者13331),一般来说P最好为素数.然后我们之所以需要前缀和,是因为我们这道题目是求一个区间的字符串,又因为是哈希表,所以我们得求出区间哈希和,又因为是是区间和,所以我们得用前缀和求O(n)预处理,来实现和哈希一般的O(1)常数级别查询.这种Hash常用,且...

without的博客 3484

关于C++中pb_ds库的一些个人思考

在pb_ds库中还有一些其他的内容,如果这么多头文件记不住,可以使用(注意:这个头文件在devc中会报错,因此需要注意自己是否需要,同时使用clang的编译器也无法使用这个头文件)这个但总体来说,在实际使用中发现一个了很尴尬的事情。那就是一般的比赛里用不上这些,会写那些题的人也基本用不上。但是也并不是一无是处,在竞赛中只要能够AC,就不用管使用的什么方式了。不说了,继续去学线段树了...如果有误,还请各个大佬指出。从pbds、rope到stl数据结构的奇技淫巧_pbds rope-优快云博客。

m0_72501100的博客 1815

哈希算法实战全景:安全加密到分布式系统的“核心引擎”

本文全面解析哈希算法在工程实践中的核心应用。哈希算法通过将任意数据转换为固定长度二进制串(MD5/SHA等),具备不可逆、敏感、低冲突和高效率等特性。其七大应用场景包括:安全加密(密码存储加盐)、唯一标识(数据去重)、数据校验(P2P下载验证)、散列函数(哈希表基础)、负载均衡(请求分发)、数据分片(分布式存储)和一致性哈希(平滑扩容)。文章通过典型案例和面试误区分析,揭示哈希算法如何成为现代分布式系统、数据安全和高效处理的核心引擎,强调其在未来技术发展中的持续重要性。

星之尘1021的博客 1187

Hierarchical-Localization 环境配置与依赖管理全攻略

本文提供了Hierarchical-Localization(hloc)视觉定位工具箱从零开始的环境配置与依赖管理全攻略。针对Windows、Ubuntu和macOS三大操作系统,详细解析了Python版本选择、PyTorch与CUDA版本匹配、pycolmap版本锁定等核心依赖的安装步骤,并汇总了权重文件格式、NumPy版本、路径配置等常见问题的排查与解决方案,旨在帮助用户高效搭建稳定的hloc开发环境。

weixin_29066781的博客 335

ExtC++(PBDS) 食用方法

说明:大量内容参考OIWIKI。

HeartFireY的博客 2019

NVIDIA GR00T SONIC - 人形机器人强化学习全身控制入门教程(一)

SONIC 是一个类人行为基础模型,它为机器人提供了一套从大规模人类动作数据中学习而来的核心运动技能。与为每个动作单独构建控制器不同,SONIC 将动作追踪作为可扩展的训练任务,因此单一套统一策略即可产生自然的全身运动,并支持多种多样的行为。         🎯 主要特点: 🚶 自然的全身运动(行走、爬行、动态动作) 🎮 支持实时 VR 遥操作 🤖 高级规划与交互的基础 📦 即用型 C++ 推理栈

2506_90492529的博客 840

C函数学习(2):GLib HashTable函数

哈希表是一种基于key-value进行访问的数据结构,可以加快查找的速度,因此在一些需要快速查找是否有重复元素的场景中,常常使用哈希表来实现。

Stoneshen的博客 2772

eCognition易康操作教程(一):如何利用eCognition易康软件进行影像分割之棋盘分割、四叉树分割、光谱差异分割

进程执行完成后,植被覆盖区域与裸地区域合并了。第三步:清除分割结果,点击“Image Objects”菜单栏,点击“Delete Level(s)”,选中“ResultLevel1”,点击”ok”删除棋盘分割结果。四叉树分割之后,有的正方形大一些,有的正方形小一些,大说明该区域的光谱特性更加均一,而小说明不太均一。Leve:选择运行算法的矢量层名称,这里选择四叉树分割算法得到的矢量层“ResultLevel2”。Image Layer weights:图层权重,这里设置为“1,1,1,1”。

蒹葭苍苍 4608

第58篇:AI技术实战:基于深度学习的智能音频内容审核系统

深度学习技术为智能音频内容审核系统提供了强大的支持,通过CNN、RNN和Transformer等模型,能够实现高效的音频内容检测和过滤。使用TensorFlow和Keras可以快速构建和训练音频审核模型,而预训练模型则可以进一步提升性能。数据预处理、特征提取和性能优化是提升智能音频审核系统性能的关键。希望本文的代码示例和注意事项能帮助你更好地理解和应用这些技术。接下来,我们将继续探索更多AI技术实战案例。

加入“Super Entity”,与全能开发团队共探AI智能体与数字人项目,开启前沿技术之旅。 706

必学算法——哈希算法

哈希算法是必须掌握的一种基础算法,在一些比较出名的竞赛acm、蓝桥杯,并且在一些公司面试题中都可能会出现,而且作为简单题我们必须要拿下,所以我们要引起重视,下面让我们来深入了解哈希算法。哈希算法,也称为散列算法,是一种数学函数或算法,它能够将任意长度的数据(称为“消息”)转换为固定长度的字符串(称为“哈希值”或简称“哈希”)。学习算法是一个很艰难,漫长的过程,我们要克服一切困难,学习算法本就是由易到难,我相信通过我们坚持不懈的努力一定能理解并熟练掌握其中细节,加油,我相信你一定能行。

ycs66的博客 5286

YOLO11全网首发:CVPR2026 MixerCSeg | DEGConv方向引导边缘门控,破解细长裂缝检测难题

DEGConv通过方向先验嵌入、边缘增强卷积和动态门控三大机制,针对性解决了YOLO在处理裂缝类细长、多方向、低对比度目标时的特征提取不足问题,显著提升了裂缝检测的精度与鲁棒性。

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 561

不用10分钟,快速理解哈希(Hash),哈希算法,哈希表

哈希是一种能将任意长度的数据输入转化为固定长度值的过程,这个固定长度的输出值被称为哈希值或者摘要。无论原始数据有多长,哈希值的长度都是固定的。

2402_89254607的博客 1436

Vue2 - 详细实现解析Markdown内容生成侧边栏Toc目录索引,识别文章内容根据大标题/小标题自动生成多级文章目录,点击目录导航时跳转到文章内容对应的锚点位置带过渡动画,滑过锚点时高亮对应标题

vue2,nuxt2,Markdown,目录,文章目录锚点,滚动高亮导航文字,根据页面滚动高亮显示目录的侧边栏,自动提取标题生成右侧目录,vuemarkdown解析并生成目录,滚动页面的时候文章目录跟着选中效果,侧边栏滚动跟随页面,右边目录固定,左边内容可以滚动并且与左边目录联动,实现监听滚动,锚点定位,文章目录滚动跟随高亮,右边菜单点击目录滚动到对应标题,报错,渲染失败,文章内容,读取#标题符号,自动生成一个目录树,自动生成Toc目录,博客内容生成目录索引,资讯文章,生成锚点目录树TOC,详细示例代码教

🏆 前端领域优质创作者 3668

图像标注神器:完全开源免费的多功能标注工具Labelme详解

Labelme是MIT开发的免费开源图像标注工具,支持多边形、矩形等多种标注类型,适用于目标检测、分割等计算机视觉任务。提供Windows可执行文件和Python安装两种方式,可输出JSON格式并转换为COCO等标准数据集。具有跨平台、功能全面、社区活跃等优势,能显著提升标注效率,是AI视觉项目的重要数据准备工具。

数字人生 528

浅谈哈希算法(Hash Algorithm)

摘要:哈希算法是信息安全领域的核心技术,通过固定长度输出和单向不可逆等特性,确保数据完整性、身份验证和敏感信息保护。核心特性包括固定长度输出、单向不可逆、抗碰撞性和雪崩效应。常见算法中,MD5和SHA-1已被破解,推荐使用SHA-256、SHA-3及专用密码哈希算法如Argon2。主要应用场景涵盖密码存储(加盐处理)、数据完整性校验、数字签名等。安全风险包括算法破解、彩虹表攻击等,需规避已破解算法并采用合规标准。正确选择和使用哈希算法对保障信息安全至关重要。

qq_42268594的博客 1114

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

加解密系列之Hash算法

本篇文章主要介绍hash加密算法相关的实现及应用场景

小迅先生的博客 4224

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

算法---哈希及其在字符串中的应用(字符串hash)

字符串哈希详解及例题

Air_thc的博客 1998

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

哈希算法入门(只包含算法竞赛部分)

哈希算法   哈希算法是一种字符串算法,哈希本质来说有很多种,但是算法竞赛中往往只涉及一种即将一个字符串记作一个k进制的数,保证每个长度,每种内容的字符串都有在k进制下的唯一表达方式,哈希算法本身是为字符串提供了一个简记的方式,这种方式往往可以使字符串的比较更加便捷快速,我们也可以将哈希看作一个函数,我们将一个字符串输入进函数中,然后返回的值就是这个字符串的另一种(唯一的)表达方式。 ...

462

C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法

一般翻译做散列、杂凑,或音译为哈希,是一个典型的利用空间换取时间的算法,把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。

Dola的博客 1912

小技巧——不安全哈希算法修复方案介绍

文章摘要:本文系统分析了不安全哈希算法的风险及解决方案。第一部分详细介绍了MD5、SHA-1等算法的安全隐患,指出这些算法已被证实存在严重碰撞漏洞,无法满足密码学安全要求,在密码存储、数字签名等场景存在重大风险。第二部分提出具体修复方案:密码存储应迁移至Bcrypt、Argon2等专用慢哈希算法;数据校验应采用SHA-2/SHA-3家族;Git系统需保持更新并关注迁移计划。文章强调应全面审计现有系统,优先处理密码存储等高危场景,使用现代密码学库实现安全升级。

zqmattack的博客 601

哈希算法——Skein算法

哈希算法——Skein算法

专注分享技术、实用优质教程、资源 1444

常见哈希算法及其应用场景

本文介绍了哈希算法及其应用,包括编码方法、密码学和非密码学哈希函数。选择合适的算法需考虑安全性、效率和数据结构需求。

陆业聪 2133

子串查找【哈希算法】

子串查找 传送门: 链接 来源: UPC8170 题目描述 给定一个字符串A和一个字符串B,求B在A中的出现次数。A和B中的字符均为英语大写字母或小写字母。 A中不同位置出现的B可重叠。 输入 输入共两行,分别是字符串A和字符串B。 输出 输出一个整数,表示B在A中的出现次数。 样例输入 zyzyzyz zyz 样例输出 3 提示 1≤A,B的长度≤10...

XJHui 1679
上一篇: 2025杭电多校1
下一篇: 快速傅立叶变换FFT初体验(复习使用)
不难不难不难
博客等级 码龄3年 83粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值