Hướng dẫn giải của [200 đề thầy Đức] Bài 162: Người hâm mộ
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
Sắp xếp người hâm mộ theo điểm giảm dần, cùng điểm thì theo tên từ điển tăng dần, rồi lấy T người đầu tiên.
Sub 1: Vét cạn chọn dần — ~O(N · T)~
Mỗi lần quét cả danh sách để chọn người "tốt nhất" còn lại, làm T lần. Đạt 14/21 test, còn lại quá giờ.
#include <bits/stdc++.h>
using namespace std;
struct NguoiHamMo {
string ten;
long long diem;
};
// Ưu tiên: điểm cao hơn trước; cùng điểm thì tên nhỏ hơn (từ điển) trước
bool uuTien(const NguoiHamMo &x, const NguoiHamMo &y) {
if (x.diem != y.diem) return x.diem > y.diem;
return x.ten < y.ten;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, T;
cin >> N >> T;
string line;
getline(cin, line); // bỏ phần còn lại của dòng đầu
vector<NguoiHamMo> ds(N);
for (int i = 0; i < N; i++) {
getline(cin, line);
while (!line.empty() && (line.back() == '\r' || line.back() == ' ')) line.pop_back();
size_t p = line.find_last_of(' '); // token cuối là điểm
string ten = line.substr(0, p);
while (!ten.empty() && ten.back() == ' ') ten.pop_back();
ds[i].ten = ten;
ds[i].diem = stoll(line.substr(p + 1));
}
// Vét cạn: chọn lần lượt người "tốt nhất" còn lại, làm T lần
vector<bool> used(N, false);
for (int t = 0; t < T; t++) {
int best = -1;
for (int i = 0; i < N; i++)
if (!used[i] && (best == -1 || uuTien(ds[i], ds[best]))) best = i;
used[best] = true;
cout << ds[best].ten << "\n";
}
return 0;
}
Sub 2: Sắp xếp — ~O(N log N)~
Sắp xếp toàn bộ danh sách bằng hàm so sánh (điểm giảm, tên tăng) rồi in T tên đầu. Đọc từng dòng và tách tên là phần trước token cuối, điểm là token cuối. Đạt 21/21 test.
#include <bits/stdc++.h>
using namespace std;
struct NguoiHamMo {
string ten;
long long diem;
};
// Ưu tiên: điểm cao hơn trước; cùng điểm thì tên nhỏ hơn (từ điển) trước
bool uuTien(const NguoiHamMo &x, const NguoiHamMo &y) {
if (x.diem != y.diem) return x.diem > y.diem;
return x.ten < y.ten;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, T;
cin >> N >> T;
string line;
getline(cin, line); // bỏ phần còn lại của dòng đầu
vector<NguoiHamMo> ds(N);
for (int i = 0; i < N; i++) {
getline(cin, line);
while (!line.empty() && (line.back() == '\r' || line.back() == ' ')) line.pop_back();
size_t p = line.find_last_of(' '); // token cuối là điểm
string ten = line.substr(0, p);
while (!ten.empty() && ten.back() == ' ') ten.pop_back();
ds[i].ten = ten;
ds[i].diem = stoll(line.substr(p + 1));
}
// Sắp xếp theo thứ tự ưu tiên, rồi lấy T người đầu
sort(ds.begin(), ds.end(), uuTien);
for (int i = 0; i < T; i++) cout << ds[i].ten << "\n";
return 0;
}
Bình luận