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.
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 OJBạn nào muốn thử nộp bài để hệ thống chấm xem có đúng hay không thì dùng link này nhé. Chưa có tài khoản thì tạo tài khoản rồi đăng nhập nộp bài thử hen.
Nộp bài trên CodeforcesLộ 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 |
Nhận xét
Đăng nhận xét