Hướng dẫn giải của [KS cụm 2 QL] Câu 3: Toan tính
Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Hướng dẫn giải
Mỗi kỳ thủ thuộc một trong bốn nhóm (giới tính và trẻ/già). Đối thủ của một kỳ thủ là các kỳ thủ cùng độ tuổi nhóm nhưng khác giới tính. Với mỗi truy vấn số báo danh X, cần đếm số đối thủ có elo nhỏ hơn elo của X. Lưu ý truy vấn đưa vào là số báo danh, không phải thứ tự dòng.
Sub 1: Vét cạn — ~O(n)~ mỗi truy vấn, dùng khi ~n \le 1000~
Với mỗi truy vấn, duyệt toàn bộ kỳ thủ và đếm người thuộc nhóm đối thủ có elo nhỏ hơn. Sub này đúng 10/20 test.
Sub 2: Sắp xếp theo nhóm — ~O((n + T) \log n)~
Gom elo của từng nhóm vào mảng riêng và sắp xếp. Mỗi truy vấn dùng lower_bound trên nhóm đối thủ để đếm số elo nhỏ hơn. Sub này đúng 20/20 test.
Chương trình hoàn chỉnh
Hàm main đọc n, T và các kỳ thủ, tạo bảng ánh xạ số báo danh sang chỉ số. Nếu n \le 1000 gọi sub 1, còn lại gọi sub 2.
#include <bits/stdc++.h>
using namespace std;
int n, T;
int A[1000005], B[1000005], C[1000005]; // số báo danh (không dùng), giới tính (1 nam, 0 nữ), tuổi
long long D[1000005]; // hệ số elo
int grp[1000005]; // nhóm: 0 = nữ trẻ, 1 = nữ già, 2 = nam trẻ, 3 = nam già
int pos[1000005]; // pos[số báo danh] = chỉ số kỳ thủ trong mảng
vector<long long> elo[4]; // elo đã sắp xếp của từng nhóm
// Nhóm của kỳ thủ i: giới tính + tuổi (già nếu >= 50)
// Đối thủ của kỳ thủ thuộc nhóm g là nhóm cùng tuổi nhưng khác giới tính: g ^ 2 (đổi giới tính)
inline int oppGroup(int g) { return g ^ 2; }
// Sub 1: vét cạn O(n) cho mỗi truy vấn. Dùng khi n <= 1000.
void sub1() {
while (T--) {
int id;
cin >> id;
int x = pos[id]; // đổi số báo danh sang chỉ số kỳ thủ
int cnt = 0;
for (int q = 1; q <= n; q++)
if (grp[q] == oppGroup(grp[x]) && D[q] < D[x]) cnt++;
cout << cnt << "\n";
}
}
// Sub 2: sắp xếp elo theo nhóm, mỗi truy vấn dùng lower_bound: O((n + T) log n)
void sub2() {
for (int g = 0; g < 4; g++) sort(elo[g].begin(), elo[g].end());
while (T--) {
int id;
cin >> id;
int x = pos[id];
auto &v = elo[oppGroup(grp[x])];
cout << (lower_bound(v.begin(), v.end(), D[x]) - v.begin()) << "\n";
}
}
int main() {
freopen("CAU3.inp", "r", stdin);
freopen("CAU3.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> T;
for (int i = 1; i <= n; i++) {
cin >> A[i] >> B[i] >> C[i] >> D[i];
pos[A[i]] = i;
int old = C[i] >= 50 ? 1 : 0;
grp[i] = (B[i] << 1) | old; // B = 1 nam, 0 nữ; old = 1 nếu già
elo[grp[i]].push_back(D[i]);
}
if (n <= 1000) sub1();
else sub2();
return 0;
}
Bình luận