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

Quy hoạch động chữ số

Mức độ: Nâng cao

Đếm các số từ 1 đến N không chứa chữ số 4. Với N = 106 thì duyệt từng số là xong. Với N = 1018, duyệt từng số cần ước lượng hàng trăm năm. Quy hoạch động chữ số giải bài này bằng vài nghìn phép tính, vì nó không xét từng số mà xét từng chữ số: N có 19 chữ số, mỗi chữ số có 10 lựa chọn.

Các bạn cần nắm vững bài Quy tắc cộng, quy tắc nhân và bài Dãy truy hồi trước khi học bài này.

Chạy tay: các số từ 0 đến 345 không chứa chữ số 4

Phần tiêu đề “Chạy tay: các số từ 0 đến 345 không chứa chữ số 4”

Viết mọi số thành 3 chữ số (thêm 0 ở đầu: 7 thành 007). Đi từ chữ số trái nhất:

  • Chữ số đầu nhỏ hơn 3 (0, 1 hoặc 2): số chắc chắn nhỏ hơn 345, hai chữ số sau tự do, mỗi chữ số có 9 lựa chọn (trừ 4). Có 3 × 9 × 9 = 243 số.
  • Chữ số đầu bằng 3: số vẫn đang bám sát 345, chữ số thứ hai không được vượt quá 4.
    • Chữ số thứ hai nhỏ hơn 4 (0, 1, 2, 3): chữ số cuối tự do, có 4 × 9 = 36 số.
    • Chữ số thứ hai bằng 4: bị cấm, dừng.

Tổng 243 + 36 = 279 số từ 0 đến 345, bỏ số 0 còn 278 số từ 1 đến 345.

Ý quan trọng nhất là trạng thái chặt: khi các chữ số đã chọn bằng đúng các chữ số đầu của N, chữ số tiếp theo không được vượt quá chữ số tương ứng của N. Chỉ cần chọn một chữ số nhỏ hơn là hết chặt, các chữ số sau tự do từ 0 đến 9.

Gọi f(vị trí, chặt) là số cách chọn các chữ số từ vị trí đó đến hết. Ở mỗi vị trí, thử mọi chữ số d được phép; chữ số tiếp theo vẫn chặt khi bây giờ đang chặt và d bằng đúng chữ số của N.

from functools import lru_cache
def dem(N):
"""Số các số từ 0 đến N không chứa chữ số 4."""
s = str(N)
@lru_cache(maxsize=None)
def f(vi_tri, chat):
if vi_tri == len(s):
return 1 # đã chọn xong một số hợp lệ
gioi_han = int(s[vi_tri]) if chat else 9
tong = 0
for d in range(gioi_han + 1):
if d == 4:
continue
tong += f(vi_tri + 1, chat and d == gioi_han)
return tong
return f(0, True)
print(dem(345) - 1) # 278 (bỏ số 0)
print(dem(10 ** 18) - 1) # 150094635296999121

Có khoảng 19 × 2 trạng thái, mỗi trạng thái thử 10 chữ số: vài trăm phép tính.

Đếm trong đoạn từ L đến R: lấy dem(R) - dem(L - 1). Đây là lý do luôn viết hàm đếm từ 0 đến N.

Điều kiện phức tạp hơn thì trạng thái cần nhớ thêm những gì cần biết về các chữ số đã chọn. Ví dụ đếm số có tổng chữ số chia hết cho k: chỉ cần nhớ tổng các chữ số đã chọn chia k dư bao nhiêu, không cần nhớ cả tổng.

f(vị trí, dư, chặt): chọn chữ số d thì dư mới là (dư + d) % k. Khi chọn xong mọi chữ số, trả về 1 nếu dư = 0, ngược lại trả về 0. Số trạng thái là 19 × k × 2.

Một vài thông tin hay gặp:

Điều kiệnCần nhớ thêm
tổng chữ số chia hết cho ktổng % k
bản thân số chia hết cho msố đã chọn % m (thêm chữ số d: (dư × 10 + d) % m)
hai chữ số kề nhau khác nhauchữ số vừa chọn
các chữ số đôi một khác nhautập các chữ số đã dùng (một số 10 bit)
có đúng k chữ số khác 0số chữ số khác 0 đã chọn

Chỉ nhớ đúng những gì cần. Trạng thái càng ít, chương trình càng nhanh.

Viết 7 thành 007 thì các chữ số 0 ở đầu không phải chữ số thật. Với điều kiện “không chứa chữ số 4” thì không sao, nhưng với điều kiện “hai chữ số kề nhau khác nhau” thì 007 bị coi là có hai số 0 kề nhau, sai. Khi đó thêm trạng thái đã bắt đầu (đã chọn chữ số khác 0 nào chưa): chừng nào chưa bắt đầu, chữ số 0 được bỏ qua, không tính vào điều kiện.

Muốn tính tổng (ví dụ tổng chữ số của mọi số từ 1 đến N), cho hàm trả về hai giá trị: số cách chọn phần còn lại, và tổng cần tính trên các cách đó. Chọn chữ số d rồi gọi phần sau được (đếm, tổng) thì phần đóng góp là (đếm, tổng + d × đếm): chữ số d có mặt trong tất cả “đếm” số.

Gồm 20 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ập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N không chứa chữ số 4?

Ví dụ: nhập 345 thì in ra 278.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

150094635296999121

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

Nhập L, R, k (1 ≤ L ≤ R ≤ 1018, 1 ≤ k ≤ 100). Có bao nhiêu số từ L đến R có tổng các chữ số chia hết cho k?

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

Kiểm tra: nhập 1 1000000000000000000 7.

Xem đáp số

142857142856594041

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

Nhập N, S (1 ≤ N ≤ 1018, 1 ≤ S ≤ 200). Có bao nhiêu số từ 1 đến N có tổng các chữ số đúng bằng S?

Ví dụ: nhập 100 10 thì in ra 9.

Kiểm tra: nhập 1000000000000000000 81.

Xem đáp số

32458256583753952

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

Viết các số từ 1 đến N liên tiếp nhau. Chữ số 1 xuất hiện tất cả bao nhiêu lần? Nhập N (1 ≤ N ≤ 1018).

Ví dụ: nhập 13 thì in ra 6.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

1800000000000000001

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

Nhập N (1 ≤ N ≤ 1018). Tính tổng các chữ số của mọi số từ 1 đến N, chia lấy dư cho 109 + 7.

Ví dụ: nhập 12 thì in ra 51.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

3970

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

Nhập L, R (1 ≤ L ≤ R ≤ 1018). Có bao nhiêu số từ L đến R mà không có hai chữ số kề nhau nào bằng nhau?

Ví dụ: nhập 1 100 thì in ra 90.

Kiểm tra: nhập 1 1000000000000000000.

Xem đáp số

168856464709124010

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

Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N mà các chữ số không giảm khi đọc từ trái sang phải (ví dụ 1129, 7, 3389)?

Ví dụ: nhập 100 thì in ra 54.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

4686824

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

Nhập N, a, b (1 ≤ N ≤ 1018, 1 ≤ a, b ≤ 60). Có bao nhiêu số từ 1 đến N vừa chia hết cho a, vừa có tổng chữ số chia hết cho b?

Ví dụ: nhập 100 5 2 thì in ra 9.

Kiểm tra: nhập 1000000000000000000 7 9.

Xem đáp số

15873015873015873

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

Nhập N và k (N là số nguyên dương có không quá 100 chữ số, 1 ≤ k ≤ 3). Có bao nhiêu số từ 1 đến N có đúng k chữ số khác 0?

Ví dụ: nhập 100 1 thì in ra 19.

Kiểm tra: nhập 31415926535897932384626433832795028841971693993751 2.

Xem đáp số

96571

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

Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N có chứa ít nhất một chữ số 0?

Ví dụ: nhập 100 thì in ra 10.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

831143535290875990

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

Đánh số vị trí các chữ số từ phải sang trái bắt đầu từ 1 (chữ số hàng đơn vị ở vị trí 1). Số cân bằng là số có tổng các chữ số ở vị trí lẻ bằng tổng các chữ số ở vị trí chẵn (ví dụ 121: 1 + 1 = 2). Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số cân bằng từ 1 đến N?

Ví dụ: nhập 100 thì in ra 9.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

32458256583753951

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

Xếp các số nguyên dương không chứa chữ số 4 theo thứ tự tăng dần: 1, 2, 3, 5, 6, … Nhập k (1 ≤ k ≤ 1017). In ra số thứ k.

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

Kiểm tra: nhập 100000000000000000.

Xem đáp số

699721659158902291

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

Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N mà chữ số 3 xuất hiện nhiều hơn chữ số 5?

Ví dụ: nhập 40 thì in ra 12.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

393056739678168650

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

Nhập N, k (1 ≤ N ≤ 1018, 1 ≤ k ≤ 60). Có bao nhiêu số từ 1 đến N mà khi viết trong hệ nhị phân có đúng k chữ số 1?

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

Kiểm tra: nhập 1000000000000000000 30.

Xem đáp số

103477184498507572

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

Nhập N (1 ≤ N ≤ 1018). Tính tổng các số từ 1 đến N có tổng chữ số chia hết cho 10, chia lấy dư cho 109 + 7.

Ví dụ: nhập 100 thì in ra 495.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

200000119

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

Nhập L, R (1 ≤ L ≤ R ≤ 1018). Có bao nhiêu số từ L đến R có tổng các chữ số là số nguyên tố?

Ví dụ: nhập 1 20 thì in ra 9.

Kiểm tra: nhập 1 1000000000000000000.

Xem đáp số

211774470093626955

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

Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N có các chữ số đôi một khác nhau (ví dụ 1023 được, 1123 không được)?

Ví dụ: nhập 100 thì in ra 90.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

8877690

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

Bài 18. Mỗi chữ số xuất hiện chẵn lần

Phần tiêu đề “Bài 18. Mỗi chữ số xuất hiện chẵn lần”

Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N mà mỗi chữ số có mặt trong nó đều xuất hiện một số chẵn lần (ví dụ 1221, 3030, 77)?

Ví dụ: nhập 100 thì in ra 9.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

2105532412794693

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

Số bậc thang là số mà hai chữ số kề nhau luôn hơn kém nhau đúng 1 (ví dụ 7, 10, 3454, 98789). Nhập L, R (1 ≤ L ≤ R, mỗi số có không quá 100 chữ số). Có bao nhiêu số bậc thang từ L đến R? In ra kết quả chia lấy dư cho 109 + 7.

Ví dụ: nhập 1 100 thì in ra 26.

Kiểm tra: nhập 1 10000000000000000000000000000000000000000000000000.

Xem đáp số

363918671

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

Nhập N (1 ≤ N ≤ 1018). Có bao nhiêu số từ 1 đến N mà khi viết ra không có chữ số 1 đứng ngay trước chữ số 3 (ví dụ 135, 2130 bị loại; 31, 103 được)?

Ví dụ: nhập 200 thì in ra 188.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

841554882220704499

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