在使用字符串哈希的过程中存在取余操作,在大数据下极易出现哈希值相等的情况
不少于 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]
循环节长度一定是区间长度的约数,所以只要枚举 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;
}