1. 程式人生 > 其它 >CF EDU 117 E - Messages

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;
}