0x00 前言
在上一节中,我们提到了哈希冲突这一在做题中极为常见的错误
点击传送门,即可阅读
在做题中,我们在处理字符串哈希的时候,有可能会遇到两个字符串(这里以字符串距离)并不相同,但是计算后的两个哈希值相同,这时候我们就需要处理哈希冲突了
0x01 正文
在面对哈希冲突时,我们除了上文中的两个方法
还可以使用 双哈希
顾名思义,将一个字符串算两遍哈希
在上一文章中我们已经写出了简单版的单哈希
h
a
s
h
(
s
)
=
Σ
i
=
0
n
s
[
i
]
∗
p
n
−
i
%
m
o
d
hash(s)=\Sigma_{i=0}^{n}s[i]*p^{n-i}\ \%mod
hash(s)=Σi=0ns[i]∗pn−i %mod
计算第二个哈希的时候,只需换一个底数和质数就可以实现
我们直接整合了一个结构体里,方便使用;
struct HASH{
long long sed,mod,h[N],pw[N];
void init(int ser_in,int mod_in){
sed=ser_in,mod=mod_in;
pw[0]=1;
for(int i=1;i<N;i++){
pw[i]=pw[i-1]*sed%mod;
}
}
void make(string s){
h[0]=s[0]%mod;
for(int i=1;i<s.size();i++){
h[i]=(h[i-1]*sed%mod+s[i])%mod;
}
}
long long get(int l,int r){
return (h[r]-h[l-1]*pw[r-l+1]%mod+mod)%mod;
}
}s1,s2;
使用时:
struct HASH{
long long sed,mod,h[N],pw[N];
void init(int ser_in,int mod_in){
sed=ser_in,mod=mod_in;
pw[0]=1;
for(int i=1;i<N;i++){
pw[i]=pw[i-1]*sed%mod;
}
}
void make(string s){
h[0]=s[0]%mod;
for(int i=1;i<s.size();i++){
h[i]=(h[i-1]*sed%mod+s[i])%mod;
}
}
long long get(int l,int r){
return (h[r]-h[l-1]*pw[r-l+1]%mod+mod)%mod;
}
}s1,s2;
s1.init(131,1000000007);
s2.init(137,998244353);//使用不同的底数和大质数进行哈希
string s;
cin>>s;
s=" "+s;
s1.make(s);
s2.make(s);//构造
s1.get(l,r);
s2.get(l,r);//区间查询
0x02 例题
这道题中,他放我们找区间内的循环节,
由此我们可以知道,这个循环节一定是区间长度的因数
但是我们不知道应该除以几,(总不能一个一个的去试吧
这时我们可以利用欧拉筛,这个东西有一个特性,他会用每个合数的最小质因子标记他
哎,我们给他反过来不就行了
利用这一特性,再存一边每个数的最小质因子,需要的时候直接访问
这样,我们使用一个while循环,每次除以当前长度的最小值因子,再利用字符串哈希去比较,这不就行啦
tips:写的时候一定要注意小细节,不然很有可能debug半天
AC代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int Ns=1e9+7;
const int N=1000005;
int prime[500020],g[500020];
bool vis[500020];
void ola(){
int cnt=0;
vis[1]=g[1]=1;
for(long long i=2;i<=500020;i++){
if(!vis[i]){
prime[++cnt]=i;
g[i]=i;
}
for(int j=1;j<=cnt&&i*prime[j]<=500020;j++){
vis[i*prime[j]]=1;
g[i*prime[j]]=prime[j];
if(i%prime[j]==0){
break;
}
}
}
}
struct HASH{
long long sed,mod,h[N],pw[N];
void init(int ser_in,int mod_in){
sed=ser_in,mod=mod_in;
pw[0]=1;
for(int i=1;i<N;i++){
pw[i]=pw[i-1]*sed%mod;
}
}
void make(string s){
h[0]=s[0]%mod;
for(int i=1;i<s.size();i++){
h[i]=(h[i-1]*sed%mod+s[i])%mod;
}
}
long long get(int l,int r){
return (h[r]-h[l-1]*pw[r-l+1]%mod+mod)%mod;
}
}s1,s2;
#define endl "\n"
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,q;string s;
cin>>n>>s>>q;
s=' '+s;
s1.init(131,998244353);
s1.make(s);
ola();
for(int Q=1;Q<=q;Q++){
int l,r;
cin>>l>>r;
int len=r-l+1;
int ans=len;
while(len>1){
int ans1=s1.get(l,r-ans/g[len]);
int ans2=s1.get(l+ans/g[len],r);
if(ans1==ans2){
ans/=g[len];
}
len/=g[len];
}
cout<<ans<<endl;
}
return 0;
}