#include <iostream>
using namespace std;
const int N = 1e5 + 10,Q = 131;
//因为ASCII码范围为 0~127,共 128个,按照经验来说,一般取 131(128 + 3)或13331,这样产生冲突的概率低
typedef unsigned long long ULL;
//选用ULL第一点是因为Q一旦次方数高了以后会出现很范围大的数
//第二点unsigned long long的范围是[0,2^64 - 1],所以超范围之后会自动进行%2^64操作
int n,m;
char str[N];
ULL h[N],p[N];
//首先是str看成是一个p进制的数,每位字符用ASCII码替代
//利用前缀哈希求出子串哈希 e.g. hash(def) = hash(abcdef) - hash(abc) * Q ^ 3
ULL get(int l,int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
//写成平常公式就是 h[r] - h[l - 1] * Q^(r-l+1)
}
int main()
{
scanf("%d%d%s",&n,&m,str + 1);
p[0] = 1;
for(int i = 1;i <= n;i++)
{
h[i] = h[i - 1] * Q + str[i];//左移一位然后加上新的字母的ASCII
p[i] = p[i - 1] * Q;//提高次幂
}
while(m--)
{
int l1,l2,r1,r2;
cin >> l1 >> r1 >> l2 >> r2;
if(get(l1,r1) == get(l2,r2))
puts("Yes");
else
puts("No");
}
return 0;
}
注意点:
串内任何数据(除去\0,因为它的ASCII为0,也正因如此不用考虑串结尾)都不要映射成p进制下的0,如下例:
e.g. 设A为0,则“A”为0,“AAAA”也为0,冲突了。
本题是在假设不会冲突的前提下提出的。