题目链接:http://codeforces.com/contest/985/problem/F
题意:取出字符串Str里的两个串S,T,问对应位置的的字符在否有一一映射关系。
思路:
字符串hash
对于每一个字母单独hash
对于一段区间,求出每个字母的hash值,然后排序,如果能匹配上,就说明在这段区间存在字母间的一一映射,可以借助2进制01进行考虑。
题解:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
using ll = long long ;
struct HS
{
int n;
char s[maxn];
ll base[2][maxn];
ll seed[2] = {31LL, 131LL};
ll mod[2] = {987654321LL, 1000000007LL};
ll Hash[2][26][maxn];
void init() {
n = strlen(s + 1);
for(int i = 0;i < 2;i ++) {
base[i][0] = 1;
for(int j = 1;j <= n;j ++) base[i][j] = base[i][j-1] * seed[i] % mod[i];
}
for(int i = 0;i < 2;i ++) {
for(int j = 1;j <= n;j ++) {
for(int k = 0;k < 26;k ++) {
Hash[i][k][j] = ( Hash[i][k][j-1] * seed[i] + (s[j] == 'a' + k) ) % mod[i];
}
}
}
}
ll getlr(int p, int k, int l, int r) {
ll tmp = ( Hash[p][k][r] - Hash[p][k][l-1] * base[p][r-l+1] );
tmp %= mod[p];
tmp += mod[p];
tmp %= mod[p];
return tmp;
}
}hs;
ll A[2][26], B[2][26];
int main()
{
int n, q;
scanf("%d %d %s", &n, &q, hs.s+1);
hs.init();
while(q --) {
int l1, l2, len;
bool fg = 1;
scanf("%d %d %d", &l1, &l2, &len);
for(int i = 0;i < 26;i ++) {
A[0][i] = hs.getlr(0, i, l1, l1 + len - 1);
B[0][i] = hs.getlr(0, i, l2, l2 + len - 1);
}
sort(A[0], A[0] + 26);
sort(B[0], B[0] + 26);
for(int i = 0;i < 26;i ++) {
if(A[0][i] != B[0][i]) {
fg = 0;
break;
}
}
if(!fg) {
puts("NO");
continue;
}
for(int i = 0;i < 26;i ++) {
A[1][i] = hs.getlr(1, i, l1, l1 + len - 1);
B[1][i] = hs.getlr(1, i, l2, l2 + len - 1);
}
sort(A[1], A[1] + 26);
sort(B[1], B[1] + 26);
for(int i = 0;i < 26;i ++) {
if(A[1][i] != B[1][i]) {
fg = 0;
break;
}
}
puts(fg ? "YES" : "NO");
}
return 0;
}