題目鏈接: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;
}