CF985F Isomorphic Strings
【题意】
定义两个字符串 S 1 , S 2 S1,S2 S1,S2同构当且仅当有一种映射关系,使得 S 1 S1 S1映射后与 S 2 S2 S2相同
然后给出一个字符串,给出Q组询问,每组询问S1字符串中 S 1 [ x ] [ x + l e n − 1 ] S1[x][x+len-1] S1[x][x+len−1]与 S 2 [ y ] [ y + l e n − 1 ] S2[y][y+len-1] S2[y][y+len−1]的子串是否是同构的
【分析】
读完题之后一头雾水。先打个暴力?TLE 9
之后只能够想正解。
我们发现两个字符串成映射关系必须满足他们的相邻相同字母的排列方式是相同的。
可能比较绕,我们通过样例来说明一下。
S1: a a b b b c aabbbc aabbbc
S2: d d e e e f ddeeef ddeeef
他们的子串排列方式都是2+3+1的(aa + bbb + c 和 dd + eee + f)
有了这个结论有什么用? 当然有用。
对于每一个字符,我们哈希出他们的位置(位置还能哈希?)
怎么哈希我就不说了吧。
例如 S 1 S1 S1
枚举a时,我们的哈希值是 ( 221111 ) (221111) (221111)
枚举b时,我们的哈希值是 ( 112221 ) (112221) (112221)
枚举c时,我们的哈希值是 ( 111112 ) (111112) (111112)
而其他字符的哈希值都是 ( 111111 ) (111111) (111111)
这样操作又有什么用?用处大着呢
我们发现对于 S 2 S2 S2的哈希值也是 ( 221111 ) , ( 1122221 ) , ( 111112 ) (221111),(1122221),(111112) (221111),(1122221),(111112),其余23个 ( 111111 ) (111111) (111111)
我们发现他们的哈希值也成对应关系
太棒了! 这样问题就可以解了!
大家知道再怎么做么?不需要 O ( 2 6 2 ) O(26^2) O(262)的枚举了。直接搞两个multiset,把26个哈希值扔进去,判两个multiset相同就行了。
算法很牛逼666
【关于哈希的玄学故事】
双哈希在这题上跑的是挺慢的,慢的测试点2300ms,时限是3s,很慌的。
三哈希肯定TLE了
有一位叫做KrK的大佬,过了G题,F题双哈希被Hack了!也是一个红名大佬Hack的
本来这个人看到Rank1
所以写哈希的时候种子最老是rand一下哈。
【代码】
头文件太长请见谅
#include <bits/stdc++.h>
using namespace std ;
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define Rep(i, a, b) for (int (i) = (a) - 1; (i) < (b); (i)++)
#define REP(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define Sort(a, len, cmp) sort(a + 1, a + len + 1, cmp)
#define ass(a, sum) memset(a, sum, sizeof(a))
#define ls ((rt) << 1)
#define rs ((rt) << 1 | 1)
#define lowbit(x) (x & -x)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define endl '\n'
#define ENDL cout << endl
#define SZ(x) ((int)x.size())
typedef long long ll ;
typedef unsigned long long ull ;
typedef vector <int> vi ;
typedef pair <int, int> pii ;
typedef pair <ll, ll> pll ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
typedef map <ll, ll> mll ;
const int N = 200010 ;
const double eps = 1e-8 ;
const int iinf = INT_MAX ;
const ll linf = 2e18 ;
const double dinf = 1e30 ;
const int MOD1 = 1000000007 ;
const int MOD2 = 1000000009 ;
const int b1 = 41 ;
const int b2 = 37 ;
inline int read(){
int X = 0, w = 0 ;
char ch = 0 ;
while (!isdigit(ch)) { w |= ch == '-' ; ch = getchar() ; }
while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar() ;
return w ? - X : X ;
}
void write(int x){
if (x < 0) putchar('-'), x = - x ;
if (x > 9) write(x / 10) ;
putchar(x % 10 + '0') ;
}
void print(int x) {
cout << x << endl ;
exit(0) ;
}
void PRINT(string x) {
cout << x << endl ;
exit(0) ;
}
void douout(double x){
printf("%lf\n", x + 0.0000000001) ;
}
pii H[30][N] ;
int pw1[N], pw2[N] ;
int n, m ;
char str[N] ;
pii Get(pii H[], int l, int r) {
pii ans = H[r] ;
l-- ;
if (l >= 0) {
ans.fi = (ans.fi - ll(H[l].fi) * pw1[r - l] % MOD1 + MOD1) % MOD1 ;
ans.se = (ans.se - ll(H[l].se) * pw2[r - l] % MOD2 + MOD2) % MOD2 ;
}
return ans ;
}
signed main() {
pw1[0] = pw2[0] = 1 ;
scanf("%d%d", &n, &m) ;
scanf("%s", str + 1) ;
for (int i = 1; i <= n; i++) {
pw1[i] = 1ll * pw1[i - 1] * b1 % MOD1 ;
pw2[i] = 1ll * pw2[i - 1] * b2 % MOD2 ;
}
for (int i = 1; i <= n; i++)
for (int j = 0; j < 26; j++) {
H[j][i].fi = (ll(H[j][i - 1].fi) * b1 + ll(1 + ('a' + j == str[i]))) % MOD1 ;
H[j][i].se = (ll(H[j][i - 1].se) * b2 + ll(1 + ('a' + j == str[i]))) % MOD2 ;
}
while (m--) {
int x, y, len ;
scanf("%d%d%d", &x, &y, &len) ;
multiset <pii> A, B ;
for (int i = 0; i < 26; i++) {
A.insert(Get(H[i], x, x + len - 1)) ;
B.insert(Get(H[i], y, y + len - 1)) ;
}
printf("%s\n", A == B ? "YES" : "NO") ;
}
}