CF EDU 117 E - Messages

E - Messages

思维

因为每个学生最多只能读 k (1 <= k <= 20) 条消息,可以从这个小数据入手

结论:最多贴 20 条消息

可以算出贴 t 条消息时,贴每条消息的贡献,取最大的 t 个贡献相加, 设贡献分别为期望 \(a_i\) 个学生能读到

若已经贴了贡献最大的 20 条,再贴一条时,相当于 \(+\frac {20}{21} *a_{21}-\frac {1}{21} * \sum\limits_{i=1}^{20} a_i\), 因为 \(a_i\) 单调递减,所以这个数一定<=0,所以贴 20 条以上没有意义

枚举贴多少条算贡献即可

\(O(n*logn+20*n*log20)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<double, int> PDI;
const int N = 2e5 + 10;
int n;
int m[N], k[N];
map<int, vector<int> > mp;

int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> m[i] >> k[i];
		mp[m[i]].push_back(k[i]);
	}
	
	int cnt = 0;
	double maxn = 0;
	int ans[30];
	for (int t = 1; t <= min(20, (int)mp.size()); t++) //钉 t 个信息
	{
		double now = 0;
		priority_queue<PDI> heap;
		for (auto [id, vt] : mp) //钉这条信息的贡献
		{
			double add = 0;
			for (auto i : vt) //哪些人要看这条信息
			{
				if (i >= t)
				{
					add += 1;                                       
				}
				else
				{
					add += (double)i / t;
				}
			}
			heap.push({add, id});
		}
		int tmp[30];
		for (int i = 1; i <= t; i++)
		{
			now += heap.top().first;
			tmp[i] = heap.top().second;
			heap.pop();
		}
		if (now > maxn)
		{
			maxn = now;
			cnt = t;
			memcpy(ans, tmp, sizeof ans);
		}
	}
	cout << cnt << endl;
	for (int i = 1; i <= cnt; i++)
		cout << ans[i] << " ";
	cout << endl;
	return 0;
}

posted @ 2022-05-12 20:00  hzy0227  阅读(18)  评论(0编辑  收藏  举报