题目
题目链接:https://www.luogu.com.cn/problem/U142342?contestId=37784
如果两个字符串 a 和 b,如果可以通过将 a 中的 (26) 种字母一一对应的替换为不重复的 (26) 种字母变成 b 的话,我们就称 a 和 b 是等价的。
例如 "zzpzpt" 和 "oofofc" 是等价的,"rrrtt" 和 "ooopp" 也是等价的,而 "qqq" 和 "ppq" 就不是,"apple" 和 "abcde" 也不是。
有一个均由小写字母构成字符串 s,长度为 (n)。
有 (m) 个询问,每个询问给定三个数字 (x,y,z),询问 s 中以 (x) 位置开头的长度为 (z) 的子串和以 (y) 位置开头的长度为 (z) 的子串是否等价。
思路
随便取一个字母 (a),在字符串中如果第 (i) 为是字母 (a) 我们就设为 (1),否则设为 (0)。
那么两个子串等价其实就是存在一种两两对应的方案,且在对应的区间内他们的 (01) 串相同。
那么将每个字母的 (01) 序列 hash 一下,然后就可以 (O(26)) 判断了。
时间复杂度 (O(26n))。
代码
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=200010;
const ull base1=131,base2=13331;
ull ha[3][27][N],power[3][N],h[5][27];
int n,m;
char ch;
int main()
{
scanf("%d%d",&n,&m);
power[1][0]=power[2][0]=1;
for (int i=1;i<=n;i++)
{
while (ch=getchar())
if (ch>='a' && ch<='z') break;
for (int j=1;j<=26;j++)
{
ha[1][j][i]=ha[1][j][i-1]*base1+(j==ch-'a'+1);
ha[2][j][i]=ha[2][j][i-1]*base2+(j==ch-'a'+1);
}
power[1][i]=power[1][i-1]*base1;
power[2][i]=power[2][i-1]*base2;
}
while (m--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
for (int i=1;i<=26;i++)
{
h[1][i]=ha[1][i][x+z-1]-ha[1][i][x-1]*power[1][z];
h[2][i]=ha[1][i][y+z-1]-ha[1][i][y-1]*power[1][z];
h[3][i]=ha[2][i][x+z-1]-ha[2][i][x-1]*power[2][z];
h[4][i]=ha[2][i][y+z-1]-ha[2][i][y-1]*power[2][z];
}
sort(h[1]+1,h[1]+27); sort(h[2]+1,h[2]+27);
sort(h[3]+1,h[3]+27); sort(h[4]+1,h[4]+27);
bool flag=1;
for (int i=1;i<=26;i++)
if (h[1][i]!=h[2][i] || h[3][i]!=h[4][i]) flag=0;
if (flag==1) printf("YES
");
else printf("NO
");
}
return 0;
}