Messages 贪心,期望,概率,模拟

在这里插入图片描述
题意 :

  • 有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+1k,因为每个人的期望是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;
}

猜你喜欢

转载自blog.csdn.net/m0_51448653/article/details/121496302