哈希冲突 笔记

哈希冲突

在使用字符串哈希的过程中存在取余操作,在大数据下极易出现哈希值相等的情况

生日悖论

不少于 23 个人中至少有两人生日相同的概率大于 50%。例如在一个 30 人的小学班级中,存在两人生日相同的概率为 70%。对于 60 人的大班,这种概率要大于 99%。

由此可见哈希冲突概率极大

So, what can we do to solve this problem?

双哈希

顾名思义,进行二次哈希值的求解,分别采用不同的模数、底数
这样,冲突的概率就大大降低了

模板

struct Hash{
	long long base,mod,has[1000005],power[1000005];
	void init(long long basein,long long modin){
		base=basein,mod=modin;
		power[0]=1;
		for(int i=1;i<1000005;i++){
			power[i]=power[i-1]*base%mod;
		}
	}
	void machen(string s){
		has[0]=s[0]%mod;
		for(int i=1;i<s.size();i++){
			has[i]=(has[i-1]*base%mod+s[i])%mod;
		}
	}
	long long get(long long l,long long r){
		return (has[r]-has[l-1]*power[r-l+1]%mod+mod)%mod;
	}
};

例题

OKR-A Horrible Poem [POI2012]

OKR-A Horrible Poem [POI2012]

循环节长度一定是区间长度的约数,所以只要枚举 R-L+1 的所有约数作为长度 len,并判断是否是循环节,利用欧拉筛,提前预处理出所有数的最小质因子,得到原串的质因子,从而枚举循环节长度

#include
using namespace std;
long long n,len,sum,q,link,recht,num;
string s;
long long prime[1000005];
bool visited[1000005];
long long g[1000005];
deque<long long>prm;
void olaprime(){
	for(int i=2;i<=n;i++){
		if(!visited[i]){
			prm.push_back(i);
			g[i]=i;
		}
		for(int j=0;j<prm.size()&&prm[j]*i<=n;j++){
			visited[prm[j]*i]=1;
			g[prm[j]*i]=prm[j];
			if(!i%prm[j]){
				break;
			}
		}
	}
}
struct Hash{
	long long base,mod,has[1000005],power[1000005];
	void init(long long basein,long long modin){
		base=basein,mod=modin;
		power[0]=1;
		for(int i=1;i<1000005;i++){
			power[i]=power[i-1]*base%mod;
		}
	}
	void machen(string s){
		has[0]=s[0]%mod;
		for(int i=1;i<s.size();i++){
			has[i]=(has[i-1]*base%mod+s[i]-'a'+1)%mod;
		}
	}
	long long get(long long l,long long r){
		return (has[r]-has[l-1]*power[r-l+1]%mod+mod)%mod;
	}
}s1,s2;
int main(){
	scanf("%lld",&n);
	olaprime();
	cin>>s;
	s=' '+s;
	s1.init(29,1000000007);
	s1.machen(s);
	scanf("%lld",&q);
	for(int i=1;i<=q;i++){
		scanf("%lld%lld",&link,&recht);
		long long antw=recht-link+1;
		long long len=recht-link+1;
		if(s1.get(link+1,recht)==s1.get(link,recht-1)){
			printf("1\n");
			continue;
		}
		antw=recht-link+1;
		while(len>1){
			if(s1.get(link+antw/g[len],recht)==s1.get(link,recht-antw/g[len])){
				antw/=g[len];
			}
			len/=g[len];
		}
		printf("%lld\n",&antw);
	}
	return 0;
}

你可能感兴趣的:(哈希算法,笔记,算法)