Định dạng số
Đề bài
Cho số nguyên dương $N$. Hãy in ra kết quả số $N$ ở định dạng: từ phải qua trái, cứ đủ 3 chữ số và vẫn còn phần bên trái thì có dấu phẩy ngăn cách.
Input: gồm 1 dòng chứa số nguyên dương $N$ $(1 \le N \le 10^{18})$.
Output: in ra định dạng của số $N$ theo như yêu cầu.
12341,234123456123,45612345671,234,567123123Lời mở đầu
Nếu được dùng chuỗi thì bài này chỉ là chèn dấu phẩy. Nhưng đề cấm mảng và chuỗi, nên ta phải "bóc" số bằng phép chia – và gặp ngay một rắc rối: phép % 1000 lấy ra nhóm 3 chữ số bên phải trước, trong khi phải in nhóm bên trái trước. Đệ quy giải quyết rắc rối này cực gọn, vì ngăn xếp lời gọi tự "đảo ngược" thứ tự giúp ta. Đây là bài rất hay để hiểu làm việc trước hay sau lời gọi đệ quy khác nhau 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$. Đề không chia subtask, và bộ test cũng không chia nhóm: độ dài $N$ trải đều từ 1 đến 18 chữ số, lẫn lộn giữa các test.
| Số test | N nhỏ nhất | N lớn nhất | Số chữ số | Có nhóm bắt đầu bằng 0 |
|---|---|---|---|---|
| 100 | 2 | 923 713 280 435 293 013 | 1 … 18 | 21 test |
Điều đáng chú ý nhất: có 21 test chứa một nhóm 3 chữ số ở giữa/cuối bắt đầu bằng 0 (kiểu ...,076,...). Đây chính là các test "bẫy" dành cho bạn nào in nhóm bằng n % 1000 mà quên bù số 0.
Ý tưởngIn phần bên trái trước, rồi mới in 3 chữ số cuối
Với $n \ge 1000$, kết quả của $n$ gồm hai phần ghép lại:
- Phần bên trái là $n / 1000$ (bỏ 3 chữ số cuối) – được định dạng theo đúng quy tắc cũ, tức là bài toán con cùng dạng, nhỏ hơn.
- Phần bên phải là dấu phẩy và đúng 3 chữ số cuối $n \bmod 1000$.
inSo(n / 1000) trước, rồi mới in , và 3 chữ số của $n \bmod 1000$.Vì lời gọi đệ quy đứng trước lệnh in, máy phải đi xuống tận nhóm trái nhất rồi mới in, sau đó in dần các nhóm còn lại khi quay lên. Chú ý nhóm 3 chữ số phải in đủ 3 chữ số: $1005$ phải ra 1,005 chứ không phải 1,5.
Em nhập $N$ rồi bấm Tiếp để xem các lời gọi đi xuống và màn hình được in ra lúc quay lên:
CodeCài đặt
if(n < 1000)là điểm dừng: còn tối đa 3 chữ số thì in thẳng, không có số 0 thừa ở đầu (nhóm trái nhất được phép ngắn hơn 3 chữ số).inSo(n / 1000)đứng trước lệnh in – đây là mấu chốt để các nhóm in ra theo đúng thứ tự từ trái sang phải.- In 3 chữ số của
rbằngr / 100,r / 10 % 10,r % 10để giữ số 0 ở đầu nhóm. Cách khác tương đương:printf(",%03d", r). - $N \le 10^{18}$ vừa trong
long long. Độ sâu đệ quy tối đa 7 lời gọi (19 chữ số).
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.025 giây.
cout << ',' << n % 1000; thì $1005$ in ra 1,5, còn $2000$ in ra 2,0. Mình chạy thử bản sai này trên bộ test: chỉ đúng 79/100 test, sai 21 test – đúng bằng số test có một nhóm (không phải nhóm đầu) bắt đầu bằng chữ số 0.
Nhận xét
Đăng nhận xét