首页 > 其他分享 >hash hash hash : ))

hash hash hash : ))

时间:2024-04-28 19:55:06浏览次数:20  
标签:hash int llu 模数 long ha

hash:

hash简述,大概就是把一个字符串映射到一个整数上(这个整数就是一个自定义进制(mode)的数),通过比较该整数匹配字符串,这样可以实现字符串之间的O(1)匹配.
为什么要按位处理,因为这样方便分离字串.
怎么映射?就是将每位(i)分离乘上\(mode^{(i-1)}\),得到的映射整型就是这个字符串的hash值.
因为这个数一般无比巨大(在我们的字符串长度较高的情况下),所以我们需要一个模数来限制其大小.
一般情况下,我们的hash值都是unsigned long long(这样int×int不会炸),前面说要有一个模数限制,这样是不会炸整型了,但是可以看出其缺点,我们可能遇到hash值相同但是不匹配的串,我们称之为hash冲突.
那么我们再想想模数的选择,应该是一个较大的质数(这样减少hash冲突).
虽说较大质数可以减少hash冲突,但还是会有冲突,怎么办呢?取两个模数,而且要是不常用的模数(因为常用的容易被定向卡).
当两个模数下的hash值均相等,那么我们认为字符串匹配.
当然,我们在用unsinged long long 类型时,因为\(2^{64}-1\)就是个质数,所以不写模数让它自然溢出在一些不卡hash冲突的题目中还是很实用的(主要咱码量小啊).
另外一个实用的技巧就是分离字串hash值,得到hash值时类似于前缀和的操作决定了分离字串hash值的近O(1)的时间复杂度(虽然常数较大),这个是十分实用的.
我们只需预处理出所有位数应该对应乘上的mode的次数(p数组)以及某个串的任意一位到初始位的hash值(ha数组),任意一个字串\([i,j]\)的hash值就可以用\(ha[j]-ha[i-1]×(pow[j-i+1])\)得到.
例题(板子):乌力波

#include<bits/stdc++.h>
#define llu unsigned long long
#define lll long long
using namespace std;
const int N=1e6+20;
const int base=113;//进制数应该是一个质数
int n,h1,h2,ans;
char c1[N],c2[N];
llu p[N];//存储对应位乘数的大小 
llu ha[N];//存储查询的字符串的子串(从起点开始)hash值. 
llu cuthash(int l,int r)
{
	return ha[r]-p[r-l+1]*ha[l-1];
}
void init()
{
	cin>>n;
	p[0]=1;
	for(int i=1;i<=N-20;i++)p[i]=p[i-1]*base;
	while(n--)
	{
		ans=0;
		cin>>(c1+1)>>(c2+1);
		int l1=strlen(c1+1),l2=strlen(c2+1);
		llu hash1=0;//存储判断的那个字符串的hash值.
		for(int i=1;i<=l1;++i)
			hash1=hash1*base+c1[i];
		for(int i=1;i<=l2;++i)
			ha[i]=ha[i-1]*base+c2[i];
		for(int i=1;i<=l2-l1+1;++i)
		{
			llu k=cuthash(i,i+l1-1);//得到大小为l1字串的hash 
			if(k==hash1)
				++ans;
		} 
		cout<<ans<<'\n';
	}
}
int main()
{
	ios::sync_with_stdio(0);
   	cin.tie(0);
   	cout.tie(0);
	init();
	return 0;
}

另外就是一个双模数哈希的写法.
前文提及,自然溢出的hash明显不保险.
所以说就有了在自然溢出基础上去再加一个模数取hash值.
(当然,理论上来讲,只要这个模数别人不知道,就无法单向卡你的模数,所以貌似不带自然溢出的单模数hash也是可以的,可省时间).
那么简单叙述一下单模数hash的写法:首先要取一个较大的质数作为模数,其他的...好像没什么可讲的.
看代码吧.

llu ha[N],p[N];
//预处理每个位置上的乘数.
for(int i=1;i<=(1e5);++i)
{
	p[i]=p[i-1]*base%mod;
}
//取hash值,注意应该是long long类型,unsigned long long不行,不知道为什么有没有神犇给蒟蒻解释下...
ll gethash(int l,int r)
{
	return (ha[r]-ha[l-1]*p[r-l+1]%mod+mod)%mod;
}
//处理串s的所有从1到now的hash值
scanf("%s",s+1);
nowlen=strlen(s+1);
for(int now=1;now<=nowlen;++now)
	ha[now]=(ha[now-1]*base%mod+s[now])%mod;

就是这样了,这个模式大概不错.
至于有没有更简便的写法...本蒟蒻不知道...希望神犇指点.
例题链接及题解链接

标签:hash,int,llu,模数,long,ha
From: https://www.cnblogs.com/shining-like-stars/p/18154398

相关文章

  • 通配符匹配|dfs,hash|题解
    [CQOI2014]通配符匹配题目描述几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个是星号(*),可以匹配0个及以上的任意字符:另一个是问号(?),可以匹配恰好一个任意字符。现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的......
  • JDK源码分析-HashSet
    概述HashSet是Java集合框架中非常重要的一个类,它实现了Set接口,不允许出现重复元素,并且元素是无序的。HashSet的底层实现主要依赖于HashMap,通过HashMap来存储元素。如果想要了解HashMap,可以查看后续文章。类图从以上类图可以看到,HashSet实现了三个接口,继承了一个抽象类:Serial......
  • springboot~redis的hash结构为key设置过期策略
    redis配置文件开启键过期#The"notify-keyspace-events"takesasargumentastringthatiscomposed#ofzeroormultiplecharacters.Theemptystringmeansthatnotifications#aredisabled.##Example:toenablelistandgenericevents,fromthepo......
  • HASHCTF2024
    SecretofKeyboard签到脚本题,有些同学的脚本解出来大小写不正确可能是由于脚本无法识别shift+字母的组合键首先使用tshark:tshark-rusb.pcap-Tfields-eusb.capdata|sed'/^\s*$/d'>usbdata.txt提取数据并删除空格然后脚本一把梭出来:keyboard.py:normalKeys={......
  • Python基础-模块和包(hashlib、random、json、time、datetime和os模块)
    什么是模块和包?模块:python中的.py文件,将一些功能按照某一种维度进行划分;自定义、内置。、第三方.包:文件夹里面好多个.py文件。在讨论的时候,一般统称为:模块。学习:自定义模块和包+使用内置模块+使用第三方模块+使用1自定义模块和包1.1快速上手-项目文件夹(......
  • 【Redis】Redis的操作命令(二)——Redis 哈希(HASH)
    Redishash是一个string类型的field(字段)和value(值)的映射表,hash特别适合用于存储对象。当设置一个名为demo的哈希对象时:HSETdemoname"redistutorial"description"redisbasiccommandsforcaching"likes20visitors23000 获取哈希对象语句,如下:HGETALLde......
  • 字符串基础:Hash,KMP,trie
    Hash把一个字符串映射成一个整数,可以方便的比较两个字符串是否相等,计算\(Hash\)值:\[\displaystyle\sum_{i=0}^{len-1}(s[i]\timesB^{len-1-i})(mod\;M)\]这里的\(B\)是任取的一个大小合适的数,\(M\)就是为了把算出来的值映射到\([0,M-1]\)的范围内,既然是\(mod\),......
  • P3667 Bovine Genomics Hash+二分题解
    砂金听说了你在学字符串,于是在CLOI里出了道题给你P3667BovineGenomics题链:洛谷hzoi提高\(hash\)基础题。思路是二分答案,\(check\)中比较每一个区间字串的\(hash\)值是否相等。比较的时候可以用\(set\)或\(map\)。\(set\)的好处在于无重元素,判断时先将\(a\)串中区间子串......
  • 模块(time、datetime、os、random、日志logging、hashlib)
    【一】time模块【1】表示时间的三种方式时间戳元组(struct_time)格式化的时间字符串:格式化的时间字符串(FromatString):'1999-12-06'【2】时间转换(1)导入时间模块importtime(2)时间戳[1]生成时间戳importtime#生成时间戳,时间戳是浮点数类型time_str=time.time......
  • Ceph的crush算法与一致性hash对比介绍
    本文分享自天翼云开发者社区《Ceph的crush算法与一致性hash对比介绍》,作者:l****n首先,我们先回顾下一致性hash以及其在经典存储系统中的应用。一致性hash的基本原理一致性hash的基本思想是,有一个hash函数,这个hash函数的值域形成了一个环(收尾相接:thelargesthashvaluewraps......