Bỏ qua để đến nội dung

Hash xâu

Mức độ: Nâng cao

So sánh hai xâu dài L mất L bước. Một bài có 105 câu hỏi “đoạn từ i đến j có giống đoạn từ k đến l không?” thì có thể mất tới 1010 bước. Hash xâu biến mỗi đoạn thành một số, rồi so sánh hai số thay vì so sánh từng ký tự. Nhờ tổng tiền tố, hash của mọi đoạn tính được trong một phép tính.

Đổi mỗi ký tự thành một số (ví dụ a → 1, b → 2, …). Hash của xâu c1c2…cL là giá trị của một đa thức tại cơ số B, lấy dư cho một số nguyên tố lớn M:

hash = (c1 × BL - 1 + c2 × BL - 2 + … + cL) mod M

Giống như đọc xâu như một số viết trong hệ cơ số B. Hai xâu giống nhau luôn có hash bằng nhau. Hai xâu khác nhau rất hiếm khi có hash bằng nhau (gọi là trùng hash), với M khoảng 109 xác suất cỡ 1 / M cho mỗi lần so sánh.

Tính H[i] là hash của i ký tự đầu: H[0] = 0, H[i] = (H[i - 1] × B + ci) mod M. Khi đó hash của đoạn từ vị trí l + 1 đến r (đánh số từ 1) là:

hash(l + 1, r) = (H[r] - H[l] × Br - l) mod M

vì H[r] chứa cả phần đầu H[l] đã bị “đẩy lên” r - l bậc. Tính sẵn lũy thừa P[k] = Bk mod M.

Xâu abab với B = 10 (không lấy dư cho dễ thấy, a = 1, b = 2): H = 0, 1, 12, 121, 1212. Đoạn từ 3 đến 4 là H[4] - H[2] × 102 = 1212 - 1200 = 12, đúng bằng hash của ab (đoạn từ 1 đến 2 cũng là H[2] = 12).

import sys
du_lieu = sys.stdin.read().split()
s, q = du_lieu[0], int(du_lieu[1])
n = len(s)
B, M = 131, (1 << 61) - 1 # M nguyên tố rất lớn, Python tính số lớn được
H = [0] * (n + 1)
P = [1] * (n + 1)
for i, c in enumerate(s):
H[i + 1] = (H[i] * B + ord(c)) % M
P[i + 1] = P[i] * B % M
def hash_doan(l, r): # đoạn s[l:r], đánh số từ 0, không gồm r
return (H[r] - H[l] * P[r - l]) % M
ket_qua = []
for t in range(q):
a, b, c, d = (int(x) for x in du_lieu[2 + 4 * t:6 + 4 * t]) # hai đoạn [a, b] và [c, d], đánh số từ 1
giong = b - a == d - c and hash_doan(a - 1, b) == hash_doan(c - 1, d)
ket_qua.append("YES" if giong else "NO")
print("\n".join(ket_qua))
  • Cơ số B lớn hơn số loại ký tự (với chữ cái và chữ số, 131 là đủ), modulo M là số nguyên tố lớn.
  • Với M = 109 + 7, mỗi lần so sánh có khả năng trùng khoảng 10-9; nhưng nếu so sánh rất nhiều cặp (ví dụ 1010 cặp xâu con) thì gần như chắc chắn có trùng. Khi đó dùng M = 261 - 1 (như chương trình trên) hoặc hai modulo khác nhau cùng lúc.
  • Hash chỉ cho biết “gần như chắc chắn bằng nhau”. Hash khác nhau thì hai xâu chắc chắn khác nhau.

Gồm 14 bài, chia thành 4 nhóm từ dễ đến khó. Mỗi bài có một dữ liệu kiểm tra: các bạn chạy chương trình của mình với dữ liệu đó rồi so với đáp số.

Dòng đầu là xâu s (chữ cái thường, 1 ≤ |s| ≤ 2 × 105) và số q (1 ≤ q ≤ 2 × 105), q dòng sau mỗi dòng có a, b, c, d. Với mỗi câu hỏi, in ra YES nếu đoạn sa…sb giống hệt đoạn sc…sd (đánh số từ 1), ngược lại NO.

Ví dụ:

NhậpIn ra
abacaba 3
1 3 5 7
1 2 3 4
2 2 6 6
YES
NO
YES

Kiểm tra: nhập

bumbiibumbii 4
1 6 7 12
1 3 7 9
4 5 10 11
2 3 5 6
Xem đáp số
YES
YES
YES
NO

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 2. Đếm số lần xuất hiện của mẫu

Phần tiêu đề “Bài 2. Đếm số lần xuất hiện của mẫu”

Dòng đầu là xâu t, dòng thứ hai là mẫu p (chữ cái thường, 1 ≤ |p| ≤ |t| ≤ 106). In ra số vị trí trong t mà p xuất hiện bắt đầu từ đó (các lần xuất hiện có thể chồng lên nhau).

Ví dụ:

NhậpIn ra
abababa
aba
3

Kiểm tra: nhập

bumbiibumbiibumbii
bii
Xem đáp số

3

Hướng dẫn giải chi tiết: liên hệ tác giả.

Dòng đầu là xâu s (chữ cái thường, 1 ≤ |s| ≤ 2 × 105) và số q (1 ≤ q ≤ 2 × 105), q dòng sau mỗi dòng có l, r. Với mỗi câu hỏi, in ra YES nếu đoạn sl…sr là xâu đối xứng, ngược lại NO.

Ví dụ:

NhậpIn ra
abacabad 3
1 7
2 4
6 8
YES
NO
NO

Kiểm tra: nhập

racecarxabba 4
1 7
2 6
9 12
7 9
Xem đáp số
YES
YES
YES
NO

Hướng dẫn giải chi tiết: liên hệ tác giả.

Dòng đầu là xâu s (chữ cái thường, 1 ≤ |s| ≤ 2 × 105) và số q (1 ≤ q ≤ 2 × 105), q dòng sau mỗi dòng có a, b, c, d. Với mỗi câu hỏi, so sánh đoạn X = sa…sb với đoạn Y = sc…sd theo thứ tự từ điển, in <, = hoặc >.

Ví dụ:

NhậpIn ra
abacabad 3
1 3 5 7
1 2 5 8
4 4 2 2
=
<
>

Kiểm tra: nhập

bumbiibumbii 4
1 6 7 12
1 4 7 9
5 6 4 5
2 2 1 3
Xem đáp số
=
>
>
>

Hướng dẫn giải chi tiết: liên hệ tác giả.

Dòng đầu là xâu t (1 ≤ |t| ≤ 2 × 105), dòng thứ hai có k và L (1 ≤ k ≤ 105, 1 ≤ L ≤ |t|), k dòng sau mỗi dòng là một mẫu dài đúng L (chữ cái thường, k × L ≤ 106). Với mỗi mẫu, in ra số lần nó xuất hiện trong t.

Ví dụ:

NhậpIn ra
abababa
3 2
ab
ba
aa
3
3
0

Kiểm tra: nhập

bumbiibumbii
4 3
bum
mbi
bii
xyz
Xem đáp số
2
2
2
0

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập xâu s (chữ cái thường, 1 ≤ |s| ≤ 106). In ra độ dài k nhỏ nhất sao cho s là một xâu độ dài k viết lặp lại nhiều lần (k phải là ước của |s|).

Ví dụ: nhập abcabcabc thì in ra 3.

Kiểm tra: nhập bumbiibumbiibumbiibumbii.

Xem đáp số

6

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập xâu s (chữ cái thường, 1 ≤ |s| ≤ 106). In ra, theo thứ tự tăng dần, mọi độ dài k (1 ≤ k nhỏ hơn |s|) mà k ký tự đầu của s giống hệt k ký tự cuối. Nếu không có, in ra -1.

Ví dụ: nhập abacaba thì in ra 1 3.

Kiểm tra: nhập aabaaabaabaa.

Xem đáp số

1 2 5

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập hai xâu s và t cùng độ dài (chữ cái thường, 1 ≤ độ dài ≤ 106) trên hai dòng. Xoay s nghĩa là chuyển một số ký tự đầu xuống cuối. In ra số lần xoay ít nhất (từ 0 đến |s| - 1 ký tự) để s thành t, hoặc -1 nếu không thể.

Ví dụ:

NhậpIn ra
abcde
cdeab
2

Kiểm tra: nhập

bumbii
iibumb
Xem đáp số

4

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập xâu s (chữ cái thường, 1 ≤ |s| ≤ 106) và số k (1 ≤ k ≤ |s|) trên hai dòng. In ra số xâu khác nhau trong các đoạn dài đúng k của s.

Ví dụ:

NhậpIn ra
abababa
3
2

Kiểm tra: nhập

bumbiibumbiibumbii
4
Xem đáp số

6

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập xâu s (chữ cái thường, 1 ≤ |s| ≤ 2000). In ra số xâu con khác rỗng khác nhau của s (xâu con là đoạn liên tiếp).

Ví dụ: nhập abab thì in ra 7.

Kiểm tra: nhập bumbiiacademy.

Xem đáp số

87

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập hai xâu s, t trên hai dòng (chữ cái thường, mỗi xâu dài từ 1 đến 105). In ra độ dài đoạn liên tiếp dài nhất có mặt trong cả hai xâu.

Ví dụ:

NhậpIn ra
abcdxyz
xyzabcd
4

Kiểm tra: nhập

bumbiiacademy
academicbumbii
Xem đáp số

6

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập xâu s (chữ cái thường, 1 ≤ |s| ≤ 105). In ra độ dài đoạn dài nhất xuất hiện ít nhất hai lần trong s (hai lần xuất hiện được chồng lên nhau), hoặc 0 nếu không có.

Ví dụ: nhập banana thì in ra 3.

Kiểm tra: nhập bumbiiacademybumbii.

Xem đáp số

6

Hướng dẫn giải chi tiết: liên hệ tác giả.

Dòng đầu là xâu t, dòng thứ hai là mẫu p (chữ cái thường, 1 ≤ |p| ≤ |t| ≤ 2 × 105). In ra số vị trí i trong t mà đoạn dài |p| bắt đầu ở i khác p tối đa một ký tự.

Ví dụ:

NhậpIn ra
abcabcabd
abc
3

Kiểm tra: nhập

bumbiibumbiibumbii
bumbie
Xem đáp số

3

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập xâu s (chữ cái thường, 1 ≤ |s| ≤ 2 × 105). In ra độ dài đoạn liên tiếp dài nhất của s là xâu đối xứng.

Ví dụ: nhập babad thì in ra 3.

Kiểm tra: nhập forgeeksskeegforabacabaxyz.

Xem đáp số

10

Hướng dẫn giải chi tiết: liên hệ tác giả.