字符串哈希
作用:快速查询子串,极快地比较两个字符串,以及还有其他用途。(比kmp泛用性更广)
原理:1. 将字符串的前缀和字符串数组想办法转换成数字;
2.前缀和字符串数组转换为数字的方式,p进制转化十进制(秦九邵),“1234” ---> 1p0+2p1+3p^2+.....
在这里使用ASCII 码作为基准数
3.大的定义域映射到小集合,利用hash,取模2^64(利用unsigned long long 自然溢出)
4.从哈希表中获取任意[l,r]这段hash值:h[r]-h[l]*p^(r-l+1) (左端向右端对齐后相减)
5.131和13331 是经验数字作为进制P
https://www.acwing.com/problem/content/843/
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL; //0~2^64-1
const int N=100010,P=131; //131 or 13331
int n,m;
char str[N];
ULL h[N],p[N];
ULL get(int l,int r){
return h[r]-h[l-1]*p[r-l+1]; //h[r]-h[l]*p^(r-l+1)
}
int main(){
cin>>n>>m;
cin>>str+1;
p[0]=1;
//make hashset base ASCII, p hex;
for(int i=1;i<=n;i++){
h[i]=h[i-1]*P+str[i]; //秦九邵
p[i]=p[i-1]*P; //save p^i
}
//matching
while(m--){
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else puts("No");
}
return 0;
}