【hash】询问等价子串
题意
如果两个字符串\(a\)和\(b\),如果可以通过将\(a\)中的\(26\)种字母一一对应的替换为不重复的\(26\)种字母变成\(b\)的话,我们就称\(a\)和\(b\)是等价的。
即判断是否可以通过一种字符的对应关系,使得\(a=b\)。
例如\(zzpzpt\)和\(oofofc\)是等价的,\(rrrtt\)和\(ooopp\)也是等价的,而\(qqq\)和\(ppq\)就不是, \(apple\)和\(abcde\)也不是。
给出一个长度为\(n\)的字符串,有\(m\)个询问,每次询问这个字符串中的两个子串是否等价。
数据范围:\(n,m\leq200000\)
思路
从是否存在一种字符的对应关系入手。
对于每个串,把每个字母是否在这一位上记为\(0\)或\(1\),形成一个\(01\)串,\(26\)个字母共有\(26\)个字符串。
对于两串的某两个字母,如果它们的\(01\)串相同,那么它们就可以互相对应。
因为一个位置上不可能同时有\(2\)个字母,所以同一个子串的每个字母的\(01\)串都不同,我们就可以用排序来一一判断是否相同。
\(01\)串就用字符串\(hash\)来快速取出。
代码
#include <cstdio>
#include <algorithm>
int n, m;
unsigned long long f[27][200001], p[200001], f1[27], f2[27];
char c[200001];
int main() {
scanf("%d %d", &n, &m);
scanf("%s", c + 1);
p[0] = 1;
for (int i = 1; i <= 26; i++)
for (int j = 1; j <= n; j++)
f[i][j] = f[i][j - 1] * 133 + (c[j] - 96 == i);
for (int i = 1; i <= n; i++)
p[i] = p[i - 1] * 133;
for (int x, y, z; m; m--) {
scanf("%d %d %d", &x, &y, &z);
for (int i = 1; i <= 26; i++)
f1[i] = f[i][x + z - 1] - f[i][x - 1] * p[z], f2[i] = f[i][y + z - 1] - f[i][y - 1] * p[z];
std::sort(f1 + 1, f1 + 27);
std::sort(f2 + 1, f2 + 27);
int flag = 0;
for (int i = 1; i <= 26; i++)
if (f1[i] != f2[i]) {
flag = 1;
printf("NO\n");
break;
}
if (!flag) printf("YES\n");
}
}

浙公网安备 33010602011771号