题意 :
- 有n个学生,给出老师希望每个学生读的一条消息 m i m_i mi和每个学生最多能读多少条消息 k i k_i ki,如果老师发生的消息大于 k i k_i ki,学生读到任意一条消息的概率是 k i 消 息 总 数 \frac{k_i}{消息总数} 消息总数ki
- 现在希望每个学生读到希望被读的那条的消息的期望和最大,求构造发送消息是哪些
思路 :
- 我们考虑新增一本书的影响,设原本期望是E,已经挑了n本书,有t个人要看这第n+1本书,而且他们看到这本书的概率和是P= ∑ k n + 1 \frac {\sum{k}}{n+1} n+1∑k,因为每个人的期望是P*1,所以他们看到这本书的期望和也是P
- 那么这本书对原期望的影响是E= n E + P n + 1 \frac{nE+P}{n+1} n+1nE+P
- 因此,P必须比E大,于是可以贪心,让 ∑ k \sum{k} ∑k大的书先选,然后枚举答案j,每个人的k=min(k, j)
- 可以发现答案很小,因k<=20,然后j>20必然会让答案减小,因此,可以直接模拟
#include <iostream>
#include <iomanip>
#include <vector>
#include <numeric>
#define pb push_back
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int main()
{
cin.tie(nullptr) -> sync_with_stdio(false);
cout << fixed << setprecision(20);
int n;
cin >> n;
vector<int> m(n + 1), k(n + 1);
int mxK = 0;
for (int i = 1; i <= n; i ++ ) cin >> m[i] >> k[i], mxK = max(mxK, k[i]);
vector<int> p(N);
for (int i = 1; i < N; i ++ ) p[i] = i;
vector<int> ans;
double res = 0.0; // 最优期望
for (int i = 1; i <= mxK; i ++ )
{
vector<double> cnt(N, 0.0);
for (int j = 1; j <= n; j ++ )
{
if (k[j] >= i) cnt[m[j]] += 1.0;
else cnt[m[j]] += (double)k[j] / i; // 当前决定一共选i本书,m[j]这本书被看到的期望为sum{k} / i
}
// 期望值从大到小
sort(p.begin() + 1, p.end(), [&](int a, int b){
return cnt[a] > cnt[b];
});
double tmp = 0.0; // 选i本书的期望
for (int j = 1; j <= i; j ++ ) tmp += cnt[p[j]];
if (tmp > res)
{
res = tmp;
ans.clear();
for (int j = 1; j <= i; j ++ ) ans.pb(p[j]);
}
}
cout << (int)ans.size() << endl;
for (auto i : ans)
cout << i << " \n"[i == ans.back()];
return 0;
}