CF1251E2
非常神的贪心,先要发现以下两个性质:
- 要花钱收买的一些人,那么肯定是在一开始就收买他们。
- 按照 m 升序排序,那么处理 m=x 时,m=1∼x−1 的人一定都投了票,不管是贿赂还是跟风。
性质一不难理解,而性质二基于性质一,在一开始收买完人后就像连锁反应一样,m 从小到大开始依次跟风。
当我们处理到 m=x 的时候,肯定是希望这些人尽可能地跟风,减少花费。
那这就要求已经投过的人尽量地多。
如果 m=x 的人无法跟风,那 m>x 的人肯定更没法跟风。
所以只能考虑 m<x 的人,按照性质二,他们一定都投票了。如果此时还没法让 m=x 的人跟风,那就只能在 m≥x 的人里选一些贿赂。
还是要记住,我们贿赂的这些人是在一开始就贿赂了的。
于是开 n 个 vector
来存储每种 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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话