Tổng tiền tố và mảng hiệu
Đề cho dãy 105 số và 105 câu hỏi “tổng từ vị trí l đến r là bao nhiêu?”. Mỗi câu hỏi cộng lại từ đầu thì tổng cộng tới 1010 phép tính, quá chậm. Tổng tiền tố chuẩn bị trước một lần, sau đó mỗi câu hỏi chỉ cần một phép trừ. Đây là kỹ thuật xuất hiện trong rất nhiều đề học sinh giỏi.
Tổng tiền tố
Phần tiêu đề “Tổng tiền tố”Với dãy a1, a2, …, an, đặt P0 = 0 và Pi = a1 + a2 + … + ai (tổng i số đầu). Tính dần: Pi = Pi - 1 + ai.
| i | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| ai | 3 | 1 | 4 | 1 | 5 | |
| Pi | 0 | 3 | 4 | 8 | 9 | 14 |
Tổng đoạn từ l đến r là tổng r số đầu bỏ đi tổng l - 1 số đầu:
tổng(l, r) = Pr - Pl - 1
Tổng từ 2 đến 4: P4 - P1 = 9 - 3 = 6 (đúng là 1 + 4 + 1).
import sysdu_lieu = sys.stdin.read().split()n, q = int(du_lieu[0]), int(du_lieu[1])a = list(map(int, du_lieu[2:2 + n]))P = [0] * (n + 1)for i in range(1, n + 1): P[i] = P[i - 1] + a[i - 1]kq = []vi_tri = 2 + nfor _ in range(q): l, r = int(du_lieu[vi_tri]), int(du_lieu[vi_tri + 1]) vi_tri += 2 kq.append(P[r] - P[l - 1])print("\n".join(map(str, kq)))#include <iostream>#include <vector>using namespace std;
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; vector<long long> P(n + 1, 0); for (int i = 1; i <= n; i++) { long long x; cin >> x; P[i] = P[i - 1] + x; } while (q--) { int l, r; cin >> l >> r; cout << P[r] - P[l - 1] << "\n"; } return 0;}Lưu ý: dùng P0 = 0 và đánh số từ 1 giúp công thức Pr - Pl - 1 đúng cả khi l = 1, không cần xử lý riêng.
Ý tưởng tổng tiền tố đã xuất hiện ở nhiều bài trước: đếm bội số trong đoạn, đếm số nguyên tố trong đoạn, đoạn có tổng chia hết cho k.
Tổng tiền tố hai chiều
Phần tiêu đề “Tổng tiền tố hai chiều”Với bảng m hàng, n cột, đặt S[i][j] = tổng hình chữ nhật từ góc trên trái (1, 1) đến ô (i, j). Tính bằng bù trừ:
S[i][j] = a[i][j] + S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1]
(phần S[i - 1][j - 1] bị cộng hai lần nên trừ đi một lần). Tổng hình chữ nhật từ (r1, c1) đến (r2, c2):
S[r2][c2] - S[r1 - 1][c2] - S[r2][c1 - 1] + S[r1 - 1][c1 - 1]
Lấy hình lớn, bỏ dải phía trên và dải bên trái, rồi cộng lại góc trên trái vì bị bỏ hai lần. Đây chính là nguyên lý bù trừ.
Mảng hiệu: cộng cả đoạn chỉ với hai phép tính
Phần tiêu đề “Mảng hiệu: cộng cả đoạn chỉ với hai phép tính”Bài toán ngược: có q lần “cộng v vào mọi phần tử từ l đến r”, cuối cùng in ra dãy. Cộng từng phần tử thì mỗi lần tốn tới n bước.
Dùng mảng hiệu D, với ý nghĩa: ai = D1 + D2 + … + Di (dãy a là tổng tiền tố của D). Cộng v vào đoạn [l, r] chỉ cần:
- Dl += v: từ vị trí l trở đi đều được cộng v.
- Dr + 1 -= v: từ vị trí r + 1 trở đi trừ lại v, nên chỉ đoạn [l, r] bị ảnh hưởng.
Làm hết q lần, cuối cùng tính tổng tiền tố của D là được dãy kết quả.
| Thao tác | D1 | D2 | D3 | D4 | D5 | D6 |
|---|---|---|---|---|---|---|
| ban đầu | 0 | 0 | 0 | 0 | 0 | 0 |
| cộng 5 vào [2, 4] | 0 | 5 | 0 | 0 | -5 | 0 |
| cộng 2 vào [1, 3] | 2 | 5 | 0 | -2 | -5 | 0 |
| tổng tiền tố → a | 2 | 7 | 7 | 5 | 0 |
Tổng tiền tố và mảng hiệu là hai phép ngược nhau: tính hiệu liền kề của P thì được a, tính tổng tiền tố của D thì được a.
Luyện tập
Phần tiêu đề “Luyện tập”Gồm 22 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ố.
Nhóm 1. Tổng tiền tố một chiều
Phần tiêu đề “Nhóm 1. Tổng tiền tố một chiều”Bài 1. Tổng đoạn
Phần tiêu đề “Bài 1. Tổng đoạn”Dòng đầu có n, q (n, q ≤ 105). Dòng thứ hai có n số nguyên (|ai| ≤ 109). Mỗi dòng trong q dòng tiếp theo có l, r (1 ≤ l ≤ r ≤ n). Với mỗi dòng, in ra tổng al + … + ar.
Ví dụ:
| Nhập | In ra |
|---|---|
5 23 1 4 1 52 41 5 | 614 |
Kiểm tra: nhập
8 45 -2 7 3 -6 4 9 -11 83 52 24 7Bài 2. Đoạn độ dài k có tổng lớn nhất
Phần tiêu đề “Bài 2. Đoạn độ dài k có tổng lớn nhất”Dòng đầu có n, k (1 ≤ k ≤ n ≤ 105). Dòng thứ hai có n số nguyên (|ai| ≤ 109). In ra tổng lớn nhất của một đoạn gồm đúng k số liên tiếp.
Ví dụ:
| Nhập | In ra |
|---|---|
5 23 1 4 1 5 | 6 |
Kiểm tra: nhập
10 32 -1 3 5 -4 6 1 -2 7 0Bài 3. Đếm đoạn có tổng bằng S
Phần tiêu đề “Bài 3. Đếm đoạn có tổng bằng S”Dòng đầu có n, S (n ≤ 105, |S| ≤ 1014). Dòng thứ hai có n số nguyên (có thể âm, |ai| ≤ 109). Đếm số đoạn liên tiếp (ít nhất một số) có tổng đúng bằng S.
Ví dụ:
| Nhập | In ra |
|---|---|
5 52 3 -1 4 2 | 2 |
Kiểm tra: nhập
8 01 -1 2 -2 3 -3 0 1Bài 4. Vị trí cân bằng
Phần tiêu đề “Bài 4. Vị trí cân bằng”Dòng đầu là n (n ≤ 105). Dòng thứ hai có n số nguyên. Tìm vị trí i nhỏ nhất (đánh số từ 1) sao cho tổng các số bên trái i bằng tổng các số bên phải i (không tính ai; bên trái vị trí 1 có tổng 0). Nếu không có in ra -1.
Ví dụ:
| Nhập | In ra |
|---|---|
51 2 3 2 1 | 3 |
Kiểm tra: nhập
7-7 1 5 2 -4 3 0Bài 5. Đoạn con tổng lớn nhất
Phần tiêu đề “Bài 5. Đoạn con tổng lớn nhất”Dòng đầu là n (n ≤ 105). Dòng thứ hai có n số nguyên (|ai| ≤ 109). In ra tổng lớn nhất của một đoạn liên tiếp gồm ít nhất một số.
Ví dụ:
| Nhập | In ra |
|---|---|
5-2 3 -1 4 -5 | 6 |
Kiểm tra: nhập
9-2 1 -3 4 -1 2 1 -5 4Bài 6. Đoạn dài nhất có tổng bằng 0
Phần tiêu đề “Bài 6. Đoạn dài nhất có tổng bằng 0”Dòng đầu là n (n ≤ 105). Dòng thứ hai có n số nguyên. In ra độ dài đoạn liên tiếp dài nhất có tổng bằng 0 (in 0 nếu không có).
Ví dụ:
| Nhập | In ra |
|---|---|
51 2 -3 3 1 | 3 |
Kiểm tra: nhập
104 -2 -2 5 1 -6 3 -3 2 1Bài 7. Đếm số 0 trong đoạn
Phần tiêu đề “Bài 7. Đếm số 0 trong đoạn”Dòng đầu có n, q (n, q ≤ 105). Dòng thứ hai có n số nguyên. Mỗi dòng trong q dòng tiếp theo có l, r. Với mỗi câu hỏi in ra số lượng số 0 trong đoạn từ l đến r.
Ví dụ:
| Nhập | In ra |
|---|---|
6 20 1 0 0 5 01 32 5 | 22 |
Kiểm tra: nhập
10 33 0 0 7 0 1 0 0 0 21 104 67 9Nhóm 2. Tổng tiền tố hai chiều
Phần tiêu đề “Nhóm 2. Tổng tiền tố hai chiều”Bài 8. Tổng hình chữ nhật con
Phần tiêu đề “Bài 8. Tổng hình chữ nhật con”Dòng đầu có m, n, q (m, n ≤ 1000, q ≤ 105). m dòng tiếp theo mỗi dòng n số nguyên. q dòng cuối mỗi dòng có r1, c1, r2, c2. Với mỗi câu hỏi in ra tổng các số trong hình chữ nhật từ ô (r1, c1) đến ô (r2, c2).
Ví dụ:
| Nhập | In ra |
|---|---|
2 3 21 2 34 5 61 1 2 22 2 2 3 | 1211 |
Kiểm tra: nhập
3 4 31 -2 3 04 5 -6 27 0 8 -11 1 3 42 2 3 31 3 2 4Bài 9. Hình vuông k × k có tổng lớn nhất
Phần tiêu đề “Bài 9. Hình vuông k × k có tổng lớn nhất”Dòng đầu có m, n, k (k ≤ m, n ≤ 1000). m dòng tiếp theo mỗi dòng n số nguyên. In ra tổng lớn nhất của một hình vuông con k × k.
Ví dụ:
| Nhập | In ra |
|---|---|
3 3 21 2 34 5 67 8 9 | 28 |
Kiểm tra: nhập
4 5 21 -1 2 0 3-2 4 1 5 -33 0 -4 2 61 2 3 -1 0Bài 10. Hình vuông không chứa ô cấm
Phần tiêu đề “Bài 10. Hình vuông không chứa ô cấm”Dòng đầu có m, n, k (k ≤ m, n ≤ 1000). m dòng tiếp theo là bản đồ gồm . (ô trống) và # (ô cấm). Đếm số hình vuông k × k chỉ gồm ô trống.
Ví dụ:
| Nhập | In ra |
|---|---|
3 3 2....#.... | 0 |
Kiểm tra: nhập
4 5 2..#.......#.......#.Bài 11. Hình chữ nhật chứa đúng k ô đen
Phần tiêu đề “Bài 11. Hình chữ nhật chứa đúng k ô đen”Dòng đầu có m, n, k (m, n ≤ 30). m dòng tiếp theo gồm các ký tự 0 (ô trắng) và 1 (ô đen). Đếm số hình chữ nhật con (cạnh song song với lưới) chứa đúng k ô đen.
Ví dụ:
| Nhập | In ra |
|---|---|
2 2 11000 | 4 |
Kiểm tra: nhập
3 4 2100101101000Nhóm 3. Mảng hiệu
Phần tiêu đề “Nhóm 3. Mảng hiệu”Bài 12. Cộng vào nhiều đoạn
Phần tiêu đề “Bài 12. Cộng vào nhiều đoạn”Dòng đầu có n, q (n, q ≤ 105). Dãy ban đầu gồm n số 0. Mỗi dòng trong q dòng tiếp theo có l, r, v: cộng v vào mọi phần tử từ l đến r. In ra dãy cuối cùng.
Ví dụ:
| Nhập | In ra |
|---|---|
5 22 4 51 3 2 | 2 7 7 5 0 |
Kiểm tra: nhập
8 41 8 13 5 105 8 -42 2 7Bài 13. Bật tắt đèn theo đoạn
Phần tiêu đề “Bài 13. Bật tắt đèn theo đoạn”Có n bóng đèn ban đầu đều tắt (n, q ≤ 105). Có q lần thao tác, mỗi lần đảo trạng thái (tắt thành sáng, sáng thành tắt) mọi bóng từ l đến r. In ra số bóng đang sáng sau cùng. Dòng đầu có n, q, mỗi dòng tiếp theo có l, r.
Ví dụ:
| Nhập | In ra |
|---|---|
5 21 32 5 | 3 |
Kiểm tra: nhập
10 41 102 54 83 3Bài 14. Số khách nhiều nhất cùng lúc
Phần tiêu đề “Bài 14. Số khách nhiều nhất cùng lúc”Khách sạn có n đơn đặt phòng (n ≤ 105), đơn thứ i ở từ ngày ai đến hết ngày bi (1 ≤ ai ≤ bi ≤ 106). Hỏi ngày đông nhất có bao nhiêu đơn đang ở?
Ví dụ:
| Nhập | In ra |
|---|---|
31 32 54 6 | 2 |
Kiểm tra: nhập
61 42 33 75 66 93 3Bài 15. Sơn tường nhiều lớp
Phần tiêu đề “Bài 15. Sơn tường nhiều lớp”Bức tường dài n ô (n ≤ 106). Có q lần sơn, lần thứ i sơn một lớp lên các ô từ li đến ri. Nhập n, q, k và q đoạn. In ra số ô được sơn đúng k lớp.
Ví dụ:
| Nhập | In ra |
|---|---|
6 3 21 32 53 4 | 2 |
Kiểm tra: nhập
10 5 11 43 68 102 29 9Bài 16. Cộng vào hình chữ nhật
Phần tiêu đề “Bài 16. Cộng vào hình chữ nhật”Bảng m × n ban đầu toàn 0 (m, n ≤ 1000, q ≤ 105). Mỗi thao tác cộng v vào hình chữ nhật từ (r1, c1) đến (r2, c2). Dòng đầu có m, n, q, mỗi dòng sau có r1, c1, r2, c2, v. In ra bảng cuối cùng.
Ví dụ:
| Nhập | In ra |
|---|---|
3 3 11 1 2 2 5 | 5 5 05 5 00 0 0 |
Kiểm tra: nhập
3 4 31 1 3 4 12 2 3 3 21 3 1 4 -1Nhóm 4. Vận dụng
Phần tiêu đề “Nhóm 4. Vận dụng”Bài 17. Đoạn dài nhất có tổng không vượt quá S
Phần tiêu đề “Bài 17. Đoạn dài nhất có tổng không vượt quá S”Dòng đầu có n, S (n ≤ 105, S ≤ 1014). Dòng thứ hai có n số nguyên dương (≤ 109). In ra độ dài đoạn liên tiếp dài nhất có tổng ≤ S (in 0 nếu không có).
Ví dụ:
| Nhập | In ra |
|---|---|
5 72 3 1 4 2 | 3 |
Kiểm tra: nhập
10 155 1 3 5 10 7 4 9 2 8Bài 18. Đoạn ngắn nhất có tổng ít nhất S
Phần tiêu đề “Bài 18. Đoạn ngắn nhất có tổng ít nhất S”Dòng đầu có n, S (n ≤ 105, S ≤ 1014). Dòng thứ hai có n số nguyên dương. In ra độ dài đoạn liên tiếp ngắn nhất có tổng ≥ S (in 0 nếu không có).
Ví dụ:
| Nhập | In ra |
|---|---|
6 72 3 1 2 4 3 | 2 |
Kiểm tra: nhập
10 201 4 2 10 2 3 1 0 7 8Bài 19. Tổng của mọi đoạn con
Phần tiêu đề “Bài 19. Tổng của mọi đoạn con”Dòng đầu là n (n ≤ 105). Dòng thứ hai có n số nguyên dương (≤ 106). In ra tổng của tất cả các tổng đoạn liên tiếp.
Ví dụ:
| Nhập | In ra |
|---|---|
31 2 3 | 20 |
Kiểm tra: nhập
64 1 7 2 5 3Bài 20. Đếm chữ A trong đoạn xâu
Phần tiêu đề “Bài 20. Đếm chữ A trong đoạn xâu”Dòng đầu là xâu s gồm chữ in hoa (độ dài ≤ 105). Dòng thứ hai là q. Mỗi dòng trong q dòng tiếp theo có l, r: in ra số chữ A trong đoạn từ ký tự thứ l đến ký tự thứ r.
Ví dụ:
| Nhập | In ra |
|---|---|
ABRACADABRA21 114 8 | 53 |
Kiểm tra: nhập
BANANAAPPLE31 62 78 11Bài 21. Đoạn có tăng dần không
Phần tiêu đề “Bài 21. Đoạn có tăng dần không”Dòng đầu có n, q (n, q ≤ 105). Dòng thứ hai có n số nguyên. Mỗi dòng trong q dòng tiếp theo có l, r: in ra YES nếu al nhỏ hơn al + 1 nhỏ hơn … nhỏ hơn ar (tăng ngặt), ngược lại NO.
Ví dụ:
| Nhập | In ra |
|---|---|
5 21 3 2 4 51 22 4 | YESNO |
Kiểm tra: nhập
8 41 2 5 5 6 8 7 91 33 44 61 8Bài 22. Khôi phục dãy từ tổng tiền tố
Phần tiêu đề “Bài 22. Khôi phục dãy từ tổng tiền tố”Dòng đầu là n (n ≤ 105). Dòng thứ hai có n số P1, …, Pn là tổng tiền tố của một dãy a. In ra dãy a.
Ví dụ:
| Nhập | In ra |
|---|---|
53 4 8 9 14 | 3 1 4 1 5 |
Kiểm tra: nhập
6-2 5 5 1 10 0