Lũy thừa 1
Đề bài
Cho một số nguyên không âm $N$. Bạn hãy tính giá trị $2^N$.
Dữ liệu nhập: gồm một số nguyên không âm duy nhất là số $N$ $(0 \le N \le 50)$.
Dữ liệu xuất: một số nguyên dương chứa giá trị $2^N$.
416Lời mở đầu
Tính lũy thừa là ví dụ kinh điển nhất khi học hàm đệ quy có giá trị trả về: mỗi lời gọi tính xong thì "trả" kết quả về cho lời gọi bên trên dùng tiếp. Bài có một cái bẫy nho nhỏ: $2^{50}$ vượt xa kiểu int. Mình sẽ giải bằng 2 cách: đệ quy từng bước $O(N)$ và đệ quy chia để trị $O(\log N)$ – nền móng của thuật toán lũy thừa nhanh sẽ học ở các bài sau.
Bấm vào nút bên dưới để nộp bài và được hệ thống CLUE OJ chấm tự động.
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ì?
| Số test | Giá trị N | Đáp án | Subtask |
|---|---|---|---|
| 51 | Test thứ $i$ có $N = i - 1$, tức là đủ mọi giá trị $N = 0, 1, \dots, 50$ | từ $2^0 = 1$ đến $2^{50} = 1.125.899.906.842.624$ | Không chia subtask |
- Test 1 có $N = 0$: đáp án là $1$ – đây chính là điểm dừng của đệ quy, đừng quên!
- Các test 32–51 ($N \ge 31$) có đáp án vượt $2^{31} - 1 \approx 2{,}1 \cdot 10^9$ – giới hạn của
int. Đáp án lớn nhất $2^{50} \approx 1{,}1 \cdot 10^{15}$ vẫn nằm gọn tronglong long(tới khoảng $9{,}2 \cdot 10^{18}$).
int thay vì long long: kết quả chỉ 31/51 test – sai từ test 32–51. Với $N = 31$ chương trình in ra -2147483648, từ $N = 32$ trở đi in ra 0. Nên kiểu trả về của hàm phải là long long.Ý tưởngHai cách chia nhỏ 2N
Cách 2 – chia đôi: đặt $h = 2^{\lfloor N/2 \rfloor}$ thì $2^N = h \cdot h$ nếu $N$ chẵn, $2^N = h \cdot h \cdot 2$ nếu $N$ lẻ. Mỗi lần gọi $N$ giảm một nửa nên chỉ cần khoảng $\log_2 N$ lời gọi.
Ví dụ $2^{13}$: $13 \to 6 \to 3 \to 1 \to 0$, chỉ 5 lời gọi; quay về: $2^0 = 1$, $2^1 = 1 \cdot 1 \cdot 2 = 2$, $2^3 = 2 \cdot 2 \cdot 2 = 8$, $2^6 = 8 \cdot 8 = 64$, $2^{13} = 64 \cdot 64 \cdot 2 = 8192$. Điều quan trọng là ở Cách 2 ta chỉ gọi luythua(n / 2) một lần, lưu vào h rồi nhân h * h. Nếu viết luythua(n / 2) * luythua(n / 2) thì cây đệ quy sẽ phân nhánh đôi và lại tốn $O(N)$ lời gọi.
Em chọn cách, nhập $N$ rồi bấm Tiếp: lời gọi đi xuống tới điểm dừng, rồi giá trị được trả ngược lên từng tầng (chữ xanh ↩):
Cách 1Đệ quy bớt 1: 2N = 2 · 2N−1
if(n == 0) return 1;– điểm dừng, cũng xử lý luôn test $N = 0$.return 2 * luythua(n - 1);– máy phải chờluythua(n - 1)tính xong mới nhân được với 2. Vì vậy các lời gọi xếp chồng trong ngăn xếp tới khi gặp điểm dừng, rồi mới lần lượt nhân ngược lên.- Kiểu trả về
long long(xem bẫy tràn số ở phần Bộ test). Hằng2kiểuintnhân vớilong longsẽ được tính theolong long, không lo tràn.
Kết quả chạy thật: bản C++ đúng 51/51 test, test đúng chạy lâu nhất 0.003s; bản Python đúng 51/51 test, test đúng chạy lâu nhất 0.022s (Python có số nguyên lớn tuỳ ý nên không lo tràn số).
Cách 2Chia để trị: 2N = (2N/2)2
long long h = luythua(n / 2);– gọi đệ quy đúng một lần cho nửa số mũ (chia nguyên).- $N$ chẵn: $2^N = h^2$. $N$ lẻ: $N = 2 \cdot \lfloor N/2 \rfloor + 1$ nên phải nhân thêm 2.
- Với $N = 50$ chỉ có 7 lời gọi ($50 \to 25 \to 12 \to 6 \to 3 \to 1 \to 0$), so với 51 lời gọi của Cách 1. Ở bài này $N$ nhỏ nên 2 cách chạy nhanh như nhau, nhưng khi số mũ lên tới $10^{18}$ (kèm phép chia lấy dư) thì chỉ Cách 2 dùng được.
Kết quả chạy thật: bản C++ đúng 51/51 test, test đúng chạy lâu nhất 0.003s; bản Python đúng 51/51 test, test đúng chạy lâu nhất 0.033s.
Tổng kếtKết quả chạy thật trên bộ test
| Cách | Ngôn ngữ | Đúng | Lâu nhất | Ghi chú |
|---|---|---|---|---|
| Cách 1 nhưng dùng int | C++ | 31/51 | 0.003s | Sai ở test 32–51 |
| 1. Bớt 1 | C++ | 51/51 | 0.003s | Full điểm |
| Python | 51/51 | 0.022s | Full điểm | |
| 2. Chia để trị | C++ | 51/51 | 0.003s | Full điểm |
| Python | 51/51 | 0.033s | Full điểm |
int chỉ đúng 31/51 test vì tràn số. Hai điều cần nhớ: (1) luôn ước lượng kết quả lớn cỡ nào để chọn kiểu dữ liệu; (2) trong chia để trị, lưu kết quả lời gọi con vào biến rồi dùng lại, đừng gọi 2 lần.- Không biết học gì trước, học gì sau, học lan man nên kiến thức bị hổng.
- Bí bài không ai gỡ, ngồi cả buổi vẫn không ra rồi bỏ cuộc.
- Code chạy được nhưng không đủ điểm, không biết sai ở đâu, chậm ở đâu.
- Không có đề thi thử và người chấm, nên không biết mình đang ở mức nào.
- Dễ nản giữa chừng khi không có ai theo sát.
- Lộ trình 111 buổi video sắp sẵn từ dòng code đầu tiên đến đề HSG thật của các tỉnh.
- Thầy trực tiếp gỡ bí, chữa bài cho từng em qua nhóm Zalo riêng.
- Hệ thống chấm bài tự động 24/7 và thi thử HSG hằng tuần để biết chính xác mình đang ở đâu.
- Đóng học phí một lần, thầy kèm lâu dài: từ thi chuyên Tin đến HSG quốc gia và cả khi lên đại học.
Nhận xét
Đăng nhận xét