Số đặc biệt 2
Đề bài
Một số gọi là số đặc biệt khi tổng các chữ số của nó là một số nguyên tố.
Yêu cầu: nhập một số $N$. Kiểm tra xem $N$ có phải là số đặc biệt hay không. Nếu $N$ là số đặc biệt thì in ra 1, ngược lại in ra 0.
Dữ liệu vào: ghi một số $N$ duy nhất $(0 \le N \le 10^5)$.
Dữ liệu ra: gồm 1 dòng: thông báo kết quả.
Ràng buộc: 80% số test có $0 \le N \le 10^5$; 20% số test không giới hạn.
14180111Giải thích: $14$ có tổng chữ số $1 + 4 = 5$ là số nguyên tố → in 1. $8$ có tổng chữ số 8 không nguyên tố → in 0. $11$ có tổng chữ số $2$ là số nguyên tố → in 1.
Lời mở đầu
Đây là câu 1 (6 điểm) của một đề thi chọn học sinh giỏi lớp 9 môn Tin học năm học 2024 – 2025. Bài gồm 2 việc quen thuộc: tính tổng chữ số và kiểm tra số nguyên tố. Trong chương Đệ quy, mình sẽ viết việc tính tổng chữ số bằng một hàm đệ quy – đây là ví dụ "nhập môn" kinh điển để thấy một bài toán được thu nhỏ dần như thế nào.
Link này chỉ học viên đã tham gia tổ chức mới vào được. Học viên nên ưu tiên nộp ở đây vì sẽ được chấm nhanh hơn.
Nộp bài trên CLUE OJLộ trình lời giải, bấm vào từng phần để nhảy tới:
Bộ testBộ test chính thức có gì?
Bộ test có 100 test, mỗi test là một số $N$:
| Test | N | Số chữ số | Đáp án 1 | Đáp án 0 |
|---|---|---|---|---|
| 1 – 3 | 14, 8, 11 | 1 – 2 | 2 | 1 |
| 4 – 100 | 2 … 97 817 | 1 – 5 | 50 | 47 |
- Test 1 – 3 là 3 ví dụ của đề. Các test còn lại là số ngẫu nhiên từ 1 đến 5 chữ số, xếp lẫn lộn, hai đáp án 0 và 1 chia gần đều.
- Đề ghi "20% số test không giới hạn" nhưng thực tế cả 100 test đều có $N \le 10^5$ (lớn nhất là 97 817), cũng không có test $N = 0$. Nghĩa là chỉ cần một subtask; mình vẫn viết thêm cách 2 đọc xâu để các bạn đi thi thật không bị bất ngờ.
Ý tưởngTổng chữ số = chữ số cuối + tổng chữ số phần còn lại
Với $n \ge 10$: chữ số cuối là $n \bmod 10$, phần còn lại (bỏ chữ số cuối) là $n / 10$. Ví dụ $1234$: chữ số cuối 4, phần còn lại 123. Vậy:
$\text{tongCS}(n)$ $= (n \bmod 10) + \text{tongCS}(n / 10)$ nếu $n \ge 10$.
Có tổng $s$ rồi thì kiểm tra nguyên tố: $s \ge 2$ và không có ước nào trong $[2, \sqrt{s}]$. Chú ý $N = 0$ hoặc $N = 10, 100, \dots$ cho tổng 0 hoặc 1 – không phải số nguyên tố.
Em nhập $N$ rồi bấm Tiếp để xem các lời gọi đi xuống, cộng dồn chữ số khi quay lên, rồi kiểm tra nguyên tố:
Cách 1Đọc N là số nguyên – đệ quy trên số
if(n < 10) return n;là điểm dừng. Nhờ điều kiện này mà $N = 0$ cũng chạy đúng (trả về 0) chứ không đệ quy mãi.- Mỗi lời gọi bỏ đi 1 chữ số, nên số lời gọi bằng số chữ số của $N$ (tối đa 6 với $N \le 10^5$).
- Hàm
nguyenTodùng điều kiệni * i <= x; tổng chữ số rất nhỏ (tối đa 45 với $N < 10^5$) nên vòng lặp chỉ vài bước.
Kết quả chạy thật: C++ đúng 100/100 test, test chậm nhất chỉ 0.004 giây. Python đúng 100/100 test, test chậm nhất chỉ 0.029 giây.
Cách 2Phòng khi N "không giới hạn" – đọc N là xâu
Đề nói 20% test "không giới hạn". Nếu $N$ thật sự có hàng trăm chữ số thì không kiểu số nguyên nào chứa nổi, nên ta đọc $N$ dạng xâu và đệ quy theo vị trí: tổng các chữ số từ vị trí $i$ đến hết = chữ số thứ $i$ + tổng từ vị trí $i + 1$. Điểm dừng là khi $i$ chạy hết xâu (tổng bằng 0).
s[i] - '0'đổi ký tự chữ số thành giá trị số (ví dụ'7' - '0' = 7).- Độ sâu đệ quy bằng độ dài xâu. Với xâu vài trăm nghìn chữ số thì C++ vẫn ổn, còn Python phải tăng
sys.setrecursionlimit(mình đặt sẵn) và có thể tràn ngăn xếp nếu xâu quá dài – khi đó dùng vòng lặp sẽ an toàn hơn.
Kết quả chạy thật: C++ đúng 100/100 test, test chậm nhất chỉ 0.004 giây. Python đúng 100/100 test, test chậm nhất chỉ 0.032 giây.
Nhận xét
Đăng nhận xét