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

Mảng đánh dấu và đếm tần suất

Mức độ: Cơ bản

Đề cho dãy 105 số, mỗi số không quá 106, hỏi có hai số nào bằng nhau không. So từng cặp thì có khoảng 5 × 109 cặp. Mảng đánh dấu dùng chính giá trị của số làm chỉ số trong mảng: gặp số x thì xem ô da_gap[x] đã được đánh dấu chưa. Mỗi số chỉ mất một bước, cả dãy chỉ 105 bước.

Tạo mảng da_gap gồm 106 + 1 ô, ban đầu toàn False. Đi lần lượt qua dãy:

  • nếu da_gap[x] đang là True thì x đã xuất hiện trước đó: có số trùng;
  • ngược lại đánh dấu da_gap[x] = True.

Dãy 4 7 2 7 5:

Số đang xétda_gap[số] trước khi xétViệc làm
4Falseđánh dấu 4
7Falseđánh dấu 7
2Falseđánh dấu 2
7Truecó số trùng
import sys
du_lieu = sys.stdin.read().split()
n = int(du_lieu[0])
a = list(map(int, du_lieu[1:1 + n])) # 0 ≤ a[i] ≤ 10^6
da_gap = [False] * (10 ** 6 + 1)
co_trung = False
for x in a:
if da_gap[x]:
co_trung = True
break
da_gap[x] = True
print("YES" if co_trung else "NO")

Mảng đánh dấu còn trả lời ngay câu hỏi “số nhỏ nhất chưa xuất hiện là số nào”: đánh dấu hết dãy, rồi đi từ 0 lên, ô đầu tiên chưa đánh dấu là đáp số.

Thay vì chỉ đánh dấu có hay không, mảng dem ghi số lần xuất hiện: gặp x thì dem[x] += 1. Từ mảng này trả lời được rất nhiều câu hỏi, mỗi câu chỉ cần nhìn vào vài ô:

Câu hỏiCách trả lời
x xuất hiện mấy lần?dem[x]
có bao nhiêu giá trị khác nhau?số ô có dem[x] lớn hơn 0
số nào xuất hiện nhiều lần nhất?ô có dem lớn nhất
có bao nhiêu cặp số bằng nhau?cộng dem[x] × (dem[x] - 1) / 2 qua mọi x

Đếm cặp có tổng bằng S cũng làm bằng mảng đếm, không cần sắp xếp. Đi lần lượt qua dãy, với mỗi số x, các số đứng trước ghép được với x là các số bằng S - x, có đúng dem[S - x] số như vậy. Cộng vào đáp số, rồi mới tăng dem[x]. Tăng sau như vậy để x không tự ghép với chính nó.

Dãy 1 4 3 2 3, S = 6:

xS - xdem[S - x] lúc đóĐáp số
1500
4200
3300
2411
3312

Hai cặp là 4 + 2 và 3 + 3.

import sys
du_lieu = sys.stdin.read().split()
n, s = int(du_lieu[0]), int(du_lieu[1])
a = list(map(int, du_lieu[2:2 + n])) # 0 ≤ a[i] ≤ 10^6
dem = [0] * (10 ** 6 + 1)
so_cap = 0
for x in a:
can = s - x
if 0 <= can <= 10 ** 6:
so_cap += dem[can]
dem[x] += 1
print(so_cap)

Lưu ý: S - x có thể âm hoặc lớn hơn 106, phải kiểm tra trước khi dùng làm chỉ số, nếu không chương trình sẽ đọc ra ngoài mảng.

Khi các số nhỏ (ví dụ điểm thi từ 0 đến 10, hoặc giá trị không quá 106), đếm tần suất xong thì đi các giá trị từ nhỏ đến lớn, in mỗi giá trị x đúng dem[x] lần là được dãy tăng dần. Cách này tốn khoảng n + (giá trị lớn nhất) bước, không cần so sánh hai số nào với nhau.

Dãy 3 1 3 0 2 1 3: dem[0] = 1, dem[1] = 2, dem[2] = 1, dem[3] = 3, in ra 0 1 1 2 3 3 3.

Khi nào dùng mảng, khi nào dùng dict hoặc map?

Phần tiêu đề “Khi nào dùng mảng, khi nào dùng dict hoặc map?”

Mảng đánh dấu cần một ô cho mỗi giá trị có thể có. Giá trị tới 106 hay 107 thì mảng vẫn vừa bộ nhớ. Giá trị tới 109 thì mảng cần 109 ô, quá lớn.

Giới hạn giá trịNên dùng
không quá khoảng 107, không âmmảng (nhanh nhất)
có số âm, nhưng trong khoảng nhỏmảng, cộng thêm một hằng số để chỉ số không âm
lớn (109, 1018) hoặc là xâudict/set (Python), map/unordered_map/set (C++)

Với giá trị lớn còn một cách khác là rời rạc hóa: đổi các giá trị về 0, 1, 2, … rồi dùng mảng như bình thường.

Gồm 22 bài, chia thành 6 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 có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra YES nếu có hai vị trí khác nhau chứa cùng một số, ngược lại in ra NO.

Ví dụ:

NhậpIn ra
5
4 7 2 7 5
YES

Kiểm tra: nhập

10
12 5 803 47 1000000 0 66 391 25 4
Xem đáp số

NO

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra số giá trị khác nhau trong dãy.

Ví dụ:

NhậpIn ra
7
3 1 3 5 1 3 2
4

Kiểm tra: nhập

12
10 20 10 30 40 20 50 10 60 30 70 20
Xem đáp số

7

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 109). In ra số tự nhiên nhỏ nhất (tính cả 0) không có mặt trong dãy.

Ví dụ:

NhậpIn ra
6
1 0 4 2 7 1
3

Kiểm tra: nhập

10
5 3 1000000000 0 2 8 1 4 9 6
Xem đáp số

7

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

Dãy gồm n - 1 số khác nhau lấy từ 1, 2, …, n, bị mất đúng một số. Dòng đầu có n (2 ≤ n ≤ 106), dòng thứ hai có n - 1 số. In ra số bị mất.

Ví dụ:

NhậpIn ra
5
3 1 5 2
4

Kiểm tra: nhập

10
7 2 9 10 1 4 6 3 8
Xem đáp số

5

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (1 ≤ ai ≤ 109). In ra YES nếu dãy chứa mỗi số 1, 2, …, n đúng một lần (thứ tự tùy ý), ngược lại in ra NO.

Ví dụ:

NhậpIn ra
5
4 1 5 3 2
YES

Kiểm tra: nhập

8
3 8 1 6 2 7 2 5
Xem đáp số

NO

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n điểm thi là số nguyên từ 0 đến 10. In ra 11 số trên một dòng: số bạn được 0 điểm, 1 điểm, …, 10 điểm.

Ví dụ:

NhậpIn ra
8
7 8 7 10 5 8 7 9
0 0 0 0 0 1 0 3 2 1 1

Kiểm tra: nhập

15
6 7 8 4 10 6 9 7 7 3 8 6 0 7 9
Xem đáp số

1 0 0 1 1 0 3 4 2 2 1

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

Dòng đầu có n (1 ≤ n ≤ 106), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra dãy đã sắp xếp tăng dần.

Ví dụ:

NhậpIn ra
7
3 1 3 0 2 1 3
0 1 1 2 3 3 3

Kiểm tra: nhập

12
50 7 1000000 7 0 33 999999 50 12 7 0 1
Xem đáp số

0 0 1 7 7 7 12 33 50 50 999999 1000000

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra số xuất hiện nhiều lần nhất và số lần xuất hiện của nó. Nếu có nhiều số cùng xuất hiện nhiều lần nhất, in số nhỏ nhất trong chúng.

Ví dụ:

NhậpIn ra
8
5 2 5 7 2 9 5 2
2 3

Kiểm tra: nhập

12
40 13 7 13 40 7 99 7 13 40 1 2
Xem đáp số

7 3

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra, theo thứ tự xuất hiện trong dãy, các số chỉ xuất hiện đúng một lần. Nếu không có số nào thì in ra -1.

Ví dụ:

NhậpIn ra
7
4 3 4 8 1 3 6
8 1 6

Kiểm tra: nhập

12
9 2 7 2 5 9 11 0 7 3 5 12
Xem đáp số

11 0 3 12

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

Hành lang có n bóng đèn đánh số 1 đến n, ban đầu đều tắt. Có m lần bật đèn, mỗi lần bật mọi bóng từ l đến r (bóng đang sáng vẫn sáng). Dòng đầu có n, m (1 ≤ n ≤ 106, 1 ≤ m ≤ 105), m dòng sau mỗi dòng có l, r (1 ≤ l ≤ r ≤ n). Tổng các độ dài r - l + 1 không quá 106. In ra số bóng đang sáng.

Ví dụ:

NhậpIn ra
10 3
2 4
3 6
9 9
6

Kiểm tra: nhập

20 4
1 5
15 20
4 8
12 12
Xem đáp số

15

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

Trên bảng viết các số từ 1 đến n. Lần lượt xóa mọi bội của k số cho trước. Dòng đầu có n, k (1 ≤ n ≤ 106, 1 ≤ k ≤ 105), dòng thứ hai có k số b1, …, bk (2 ≤ bi ≤ n, có thể trùng nhau). In ra số lượng số còn lại trên bảng.

Ví dụ:

NhậpIn ra
20 2
4 6
13

Kiểm tra: nhập

100 3
6 10 15
Xem đáp số

74

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

Dòng đầu có n, S (1 ≤ n ≤ 105, 0 ≤ S ≤ 2 × 106), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106), chưa sắp xếp, có thể trùng. In ra số cặp vị trí i, j với i đứng trước j và ai + aj = S.

Ví dụ:

NhậpIn ra
5 6
1 4 3 2 3
2

Kiểm tra: nhập

12 10
5 5 3 7 5 1 9 2 8 0 10 5
Xem đáp số

10

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra số cặp vị trí i, j với i đứng trước j và ai = aj.

Ví dụ:

NhậpIn ra
6
3 1 3 3 1 2
4

Kiểm tra: nhập

12
7 7 7 7 2 5 2 9 5 7 9 9
Xem đáp số

15

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

Dòng đầu có n, D (1 ≤ n ≤ 105, 1 ≤ D ≤ 106), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106). In ra số cặp vị trí khác nhau (không kể thứ tự) mà hai số chênh nhau đúng D.

Ví dụ:

NhậpIn ra
6 2
1 3 5 3 7 2
5

Kiểm tra: nhập

12 5
10 5 15 0 5 20 10 25 3 8 13 8
Xem đáp số

14

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

Dòng đầu có n, q (1 ≤ n, q ≤ 105), dòng thứ hai có n số nguyên (0 ≤ ai ≤ 106), dòng thứ ba có q số x1, …, xq (0 ≤ xj ≤ 106). Với mỗi xj, in ra số lần xj xuất hiện trong dãy, các kết quả cách nhau một dấu cách.

Ví dụ:

NhậpIn ra
6 3
2 5 2 8 2 5
2 5 7
3 2 0

Kiểm tra: nhập

10 5
9 0 9 4 1000000 9 4 3 0 9
9 4 1000000 5 0
Xem đáp số

4 2 1 0 2

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

Dòng đầu có n, m (1 ≤ m ≤ n ≤ 105), dòng thứ hai có n số nguyên từ 1 đến m. In ra số k nhỏ nhất sao cho k số đầu tiên của dãy chứa đủ cả m giá trị 1, 2, …, m. Nếu cả dãy cũng không đủ, in ra -1.

Ví dụ:

NhậpIn ra
8 3
1 1 2 1 3 2 3 1
5

Kiểm tra: nhập

12 5
2 4 2 1 4 4 5 2 1 3 5 1
Xem đáp số

10

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

Nhập hai xâu s và t trên hai dòng, gồm chữ cái thường, mỗi xâu dài từ 1 đến 105. In ra YES nếu t là một cách sắp xếp lại các chữ cái của s (mỗi chữ cái xuất hiện cùng số lần trong hai xâu), ngược lại in ra NO.

Ví dụ:

NhậpIn ra
listen
silent
YES

Kiểm tra: nhập

bumbiiacademy
academybiimub
Xem đáp số

YES

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

Nhập một xâu gồm chữ cái thường (1 ≤ độ dài ≤ 105). In ra chữ cái xuất hiện nhiều lần nhất và số lần xuất hiện. Nếu có nhiều chữ cùng nhiều lần nhất, in chữ đứng trước trong bảng chữ cái.

Ví dụ: nhập bumbiiacademy thì in ra a 2.

Kiểm tra: nhập thequickbrownfoxjumpsoverthelazydog.

Xem đáp số

o 4

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

Nhập một xâu gồm chữ cái thường (1 ≤ độ dài ≤ 105). In ra vị trí (đánh số từ 1) của ký tự đầu tiên chỉ xuất hiện một lần trong xâu. Nếu không có, in ra -1.

Ví dụ: nhập lollipop thì in ra 5.

Kiểm tra: nhập abacabadabacabae.

Xem đáp số

8

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (|ai| ≤ 1018). In ra số giá trị khác nhau.

Ví dụ:

NhậpIn ra
6
1000000000000 -5 7 -5 1000000000000 0
4

Kiểm tra: nhập

10
-1 999999999999999999 -1 3 -1000000000000000000 3 42 42 7 999999999999999999
Xem đáp số

6

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

Dòng đầu có n (1 ≤ n ≤ 105), dòng thứ hai có n số nguyên (|ai| ≤ 109). In ra số xuất hiện nhiều hơn n/2 lần, hoặc -1000000001 nếu không có số nào như vậy.

Ví dụ:

NhậpIn ra
7
3 9 3 3 -2 3 9
3

Kiểm tra: nhập

10
-7 4 -7 4 4 -7 4 -7 -7 4
Xem đáp số

-1000000001

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

Bài 22. Cặp có tổng bằng S, giá trị lớn

Phần tiêu đề “Bài 22. Cặp có tổng bằng S, giá trị lớn”

Dòng đầu có n, S (1 ≤ n ≤ 105, |S| ≤ 2 × 109), dòng thứ hai có n số nguyên (|ai| ≤ 109). In ra số cặp vị trí i, j với i đứng trước j và ai + aj = S.

Ví dụ:

NhậpIn ra
6 0
-3 5 3 -5 3 0
3

Kiểm tra: nhập

10 1000000000
500000000 -1000000000 0 1000000000 500000000 999999999 1 500000000 2000000000 -1000000000
Xem đáp số

7

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