CF1251E2

非常神的贪心,先要发现以下两个性质:

  • 要花钱收买的一些人,那么肯定是在一开始就收买他们。
  • 按照 m 升序排序,那么处理 m=x 时,m=1x1 的人一定都投了票,不管是贿赂还是跟风。

性质一不难理解,而性质二基于性质一,在一开始收买完人后就像连锁反应一样,m 从小到大开始依次跟风。

当我们处理到 m=x 的时候,肯定是希望这些人尽可能地跟风,减少花费。

那这就要求已经投过的人尽量地多。

如果 m=x 的人无法跟风,那 m>x 的人肯定更没法跟风。

所以只能考虑 m<x 的人,按照性质二,他们一定都投票了。如果此时还没法让 m=x 的人跟风,那就只能在 mx 的人里选一些贿赂。

还是要记住,我们贿赂的这些人是在一开始就贿赂了的。

于是开 nvector 来存储每种 m 对应的所有 p,倒序遍历,如果后面买的人加上前面所有人的数量仍然小于当前的 m,就从后面没买的人中选若干个贿赂,这可以用一个小根堆来实现。

时间复杂度 O(nlogn)

Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200005;
int T;
int n;
vector <int> vec[N];
priority_queue <int, vector <int>, greater <int> > q;
ll ans;

void solve() {
	scanf("%d", &n);
	for (int i = 0; i < n; ++i) vec[i].clear();
	while (!q.empty()) q.pop();
	for (int i = 1, x, y; i <= n; ++i) scanf("%d%d", &x, &y), vec[x].push_back(y);
	int tot = n, cur = 0; ans = 0;
	for (int i = n - 1; ~i; --i) {
		if (vec[i].empty()) continue;
		tot -= vec[i].size(); for (auto x : vec[i]) q.push(x);
		while (cur < i - tot) ++cur, ans += q.top(), q.pop();
	}
	printf("%lld\n", ans);
}

int main() {
	scanf("%d", &T);
	while (T--) solve();
	return 0;
}
posted @   Kobe303  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示