Số lượng tối thiểu
Đề bài
Khu phố nhà Mai đã bị phong toả do mới phát sinh một số ca nhiễm Covid-19. Có $N$ người thuộc diện phải cách ly y tế. Để theo dõi mức độ phòng chống dịch của địa phương, cán bộ y tế đã thực hiện điều tra toàn bộ khu phố và cho kết quả là chỉ có đúng $a$ người trong số $N$ người này biết cách thực hiện tốt việc cách ly, những người không biết thì chắc chắn là sẽ không cách ly tốt. Do sơ suất nên cán bộ y tế chỉ ghi được danh sách $b$ người không thực hiện tốt cách ly, danh sách này có thể chưa đầy đủ nhưng cán bộ này đảm bảo rằng những người đã biết cách thực hiện mà không có tên trong danh sách là những người đã thực hiện tốt.
Yêu cầu: xác định số lượng tối thiểu và tối đa người đã thực hiện tốt việc cách ly.
Dữ liệu: gồm ba số nguyên $N$, $a$ và $b$ $(1 \le N \le 10^{18};\ 0 \le a, b \le N)$.
Kết quả: ghi ra hai số nguyên là số lượng tối thiểu và số lượng tối đa người thực hiện tốt việc cách ly.
3 2 11 2Giải thích: có 3 người, 2 người biết cách (gọi là A, B), 1 người không biết (C), danh sách ghi 1 người cách ly không tốt. Nếu danh sách ghi tên C thì A, B đều cách ly tốt → 2 người. Nếu danh sách ghi tên A thì chỉ còn B cách ly tốt → 1 người. Vậy tối thiểu 1, tối đa 2.
Lời mở đầu
Bài ngắn gọn nhưng đọc đề hơi "xoắn". Mình sẽ chuyển câu chữ thành 4 nhóm người để thấy rõ đáp án, sau đó đi từ cách thử mọi khả năng (dễ nghĩ, nhưng chậm khi $N$ tới $10^{18}$) tới công thức $O(1)$ bằng lập luận tham lam. Chú ý $N$ tới $10^{18}$ nên mọi biến phải là long long.
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ì?
Bộ test có 100 test, đề không chia subtask; $N$ tăng dần theo thứ tự test, từ $1$ tới cỡ $8 \cdot 10^{17}$ (test 99). Mình chia thành 5 nhóm theo độ lớn của $N$ để xem cách 1 trụ được tới đâu:
| Test | N | min(a, b) lớn nhất | Cách 1 C++ | Cách 2 C++ |
|---|---|---|---|---|
| 1 – 20 | $1$ … $99$ | $14$ | 20/20 | 20/20 |
| 21 – 40 | $549$ … $736.408$ | $86.622$ | 20/20 | 20/20 |
| 41 – 60 | $2,0·10^6$ … $8,8·10^9$ | $32.235$ | 20/20 | 20/20 |
| 61 – 80 | $3,1·10^10$ … $5,8·10^13$ | $9,4·10^9$ | 19/20 | 20/20 |
| 81 – 100 | $3,3·10^14$ … $7,9·10^17$ | $8,2·10^13$ | 16/20 | 20/20 |
Trường hợp đặc biệt: 49 test có đáp án tối thiểu bằng 0 (danh sách đủ dài để "nuốt" hết người biết cách, $b \ge a$), 7 test có tối thiểu = tối đa (ví dụ $a = 0$ hoặc $b = 0$ hoặc $b = N$), và 6 test có $a + b > N$ – lúc này danh sách bắt buộc phải chứa người biết cách nên tối đa nhỏ hơn $a$.
Ý tưởng4 nhóm người
Mỗi người có 2 thuộc tính: biết / không biết cách cách ly, và có / không có tên trong danh sách. Gọi $t$ là số người biết cách mà vẫn có tên trong danh sách. Khi đó:
| Có tên trong danh sách | Không có tên | Tổng | |
|---|---|---|---|
| Biết cách | $t$ (cách ly không tốt) | $a - t$ (cách ly tốt) | $a$ |
| Không biết | $b - t$ (không tốt) | $N - a - b + t$ (không tốt) | $N - a$ |
| Tổng | $b$ | $N - b$ | $N$ |
Người cách ly tốt chỉ có thể là ô "biết cách, không có tên": đúng $a - t$ người (người không biết thì chắc chắn không tốt, người có tên thì đã bị ghi là không tốt). Bốn ô trong bảng đều phải $\ge 0$:
Hiểu theo kiểu tham lam: muốn ít người tốt nhất thì "dồn" danh sách vào những người biết cách càng nhiều càng tốt ($t = \min(a, b)$); muốn nhiều người tốt nhất thì dồn danh sách vào những người không biết trước ($N - a$ chỗ), hết chỗ mới phải ghi lên người biết cách ($t = \max(0, a + b - N)$).
Em nhập $N, a, b$ nhỏ rồi bấm Tiếp để xem danh sách được "rải" lên từng người với mọi giá trị $t$:
Cách 1Thử mọi giá trị t – O(min(a, b))
Duyệt $t$ từ $0$ đến $\min(a, b)$; giá trị nào làm nhóm "không biết, có tên" vượt quá số người không biết ($b - t > N - a$) thì bỏ qua; còn lại cập nhật min/max của $a - t$.
- Điều kiện
b - t > N - a: danh sách còn $b - t$ người phải là người không biết, mà chỉ có $N - a$ người không biết. - Vòng lặp chạy $\min(a, b) + 1$ lần. Với $a, b$ cỡ $10^{12}$ trở lên thì không bao giờ chạy xong trong 1 giây.
Cách 2Công thức tham lam – O(1)
Thay hai đầu mút của $t$ vào $a - t$:
Tối đa $= a - \max(0,\ a + b - N)$ $= \min(a,\ N - b)$
0LL: số 0 kiểulong long– hàmmaxcủa C++ đòi 2 tham số cùng kiểu, viếtmax(0, a - b)sẽ báo lỗi biên dịch.- Không có phép cộng $a + b$ nên không lo tràn số (dù $a + b \le 2 \cdot 10^{18}$ vẫn vừa
long long).
Tổng kếtSo sánh 2 cách
| Cách | Độ phức tạp | C++ | Python |
|---|---|---|---|
| 1. Thử mọi t | $O(\min(a, b))$ | 95/100 | 88/100 |
| 2. Công thức | $O(1)$ | 100/100 | 100/100 |
- 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