字符串哈希
字符串哈希
题目:AcWing841
首先处理出每个前缀字符串的哈希值
求[l,r]
的子串的哈希值
如何处理出前缀字符串的哈希值
将这个前缀字符串看做一个P进制的数,将其映射成一个十进制的数(这个数就是hash值)
比如ABCDE
的子串ABC
这个前缀字符串的哈希值可以映射为(1*P^2 + 2*P^1 + 3*P^0) mod Q
(一定要从1开始映射)
在做映射的时候P
要取131
或13331
,Q
要取2^64
,c++中用unsigned long long
就可以不用mod Q了,因为溢出就相当于mod
可以预处理出来每个字符的哈希值和对应的P的幂
p[0] = 1;
for(int i = 1 ; i <= n ; i++)
{
h[i] = h[i-1] * P + str[i];
p[i] = p[i-1] * P;
}
求[l,r]
对应的子串的哈希值
视频12分钟处可以推得[l,r]
对应的子串的哈希值为h[r]-h[l-1]*P^(r-l+1)
获得[l,r]
子串的哈希值代码
typedef unsigned long long ULL;
ULL get(int l,int r)
{
return h[r] - h[l-1] *p[r-l+1];
}
代码
可以快速统计出某个字符串[l1,r1]
与[l2,r2]
的子串是否相同
#include<iostream>
#include<algorithm>
using namespace std ;
typedef unsigned long long ULL;
const int N = 100010 , P = 131;
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];
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",str + 1);
p[0] = 1;
for(int i = 1 ; i <= n; i ++)
{
h[i] = h[i-1] * P + str[i];
p[i] = p[i-1] * P;
}
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;
}
rds_blogs