【Messages】
定义为读到需要的信息的学生的数量,其中为第个学生是否读到自己需要的信息,如果读到就为,否则为。
根据期望的可加性可知:
对于每一个来说:
故:
若顶置的消息集合为: ,则:
因为我们要选取一个集合使得期望最大,所以当固定时,我们可以贪心的选取集合。
又因,故当时,:
需要先将的值排序并做前缀和,然后再枚举的值。
当时,可以暴力枚举。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m[N], k[N];
double f(int t) { // 固定t时的最优选取
unordered_map<int, double> val;
for (int i = 1; i <= n; i++) {
if (t <= k[i])
val[m[i]] += 1;
else
val[m[i]] += (1.0 * k[i]) / t;
}
vector<pair<int, double>> vec;
for (auto it : val) vec.push_back({it.first, it.second});
sort(vec.begin(), vec.end(),
[](auto a, auto b) { return a.second > b.second; });
double sum = 0;
for (int i = 0; i < min(t, (int)vec.size()); i++) sum += vec[i].second;
return sum;
}
void print(int t) {
unordered_map<int, double> val;
for (int i = 1; i <= n; i++) {
if (t <= k[i])
val[m[i]] += 1;
else
val[m[i]] += 1.0 * k[i] / t;
}
vector<pair<int, double>> vec;
for (auto it : val) vec.push_back({it.first, it.second});
sort(vec.begin(), vec.end(),
[](auto a, auto b) { return a.second > b.second; });
cout << t << "\n";
for (int i = 0; i < t; i++) cout << vec[i].first << " ";
}
double maxn = -1;
int res = -1;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> m[i] >> k[i];
// 当1 < t <= 20时
for (int t = 1; t <= 20; t++) {
double sum = f(t);
if (sum > maxn) maxn = sum, res = t;
}
// 预处理:排序,前缀和
unordered_map<int, double> val;
for (int i = 1; i <= n; i++) val[m[i]] += k[i];
vector<pair<int, double>> vec;
for (auto it : val) vec.push_back({it.first, it.second});
sort(vec.begin(), vec.end(),
[](auto a, auto b) { return a.second > b.second; });
for (int i = 1; i < vec.size(); i++) vec[i].second += vec[i - 1].second;
// 当t > 20时
for (int t = 21; t <= vec.size(); t++) {
double tmp = 1.0 * vec[t - 1].second / t;
if (tmp > maxn) maxn = tmp, res = t;
}
print(res); // 输出结果
return 0;
}