【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");
	}
}
posted @ 2020-11-26 19:34  nymph181  阅读(160)  评论(0)    收藏  举报