Educational CF Round 75 (Div. 2)___E2. Voting —— 思维

题目链接:点我啊╭(╯^╰)╮

题目大意:

    要获得 n n n 个人所有的投票
    对于一个人,如果已经有 m m m 个人投了票,则这个人可以免费投票
    或者花费 p p p 让这个人投票
    求最小花费

解题思路:

    通过贪心选取,可以发现
    对于一个还未投票的人 i i i ,最贪心的方式是在 ≥ m i ≥m_i mi 的人里选一部分人
    让当前人数到达 m i mi mi 后,让这个人免费投票

    我们不妨倒过来思考,反向枚举 m m m
    对于一个 m i m_i mi ,我们肯定是已经让小于 m i m_i mi 的人全都投了票
    然后将还未投票的(也就是 ≥ m i ≥m_i mi 的人) p p p 放到优先队列里
    在优先队列里选取一部分人,让当前人数到达 m i m_i mi

    因此, q . s i z e ( ) q.size() q.size() 表示还未投票的, n − q . s i z e ( ) n-q.size() nq.size() 表示已经投票的人数
    从队列里贪心选取较小的 p p p,直到 n − q . s i z e ( ) ≥ m i n - q.size() ≥ m_i nq.size()mi

核心:反向思维

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <ll,int>;
const int maxn = 2e5 + 5;
int T, n; 
vector <int> a[maxn];
priority_queue <int> q;

int main() {
	scanf("%d", &T);
	while(T--){
		scanf("%d", &n);
		for(int i=0; i<=n; i++) a[i].clear();
		for(int i=1; i<=n; i++)	{
			int p, m;
			scanf("%d%d", &m, &p);
			a[m].push_back(p);
		}
		while(q.size()) q.pop();
		ll ans = 0;
		for(int i=n; ~i; i--){
			for(auto p : a[i]) q.push(-p);
			while(n - q.size() < i) {
				ans -= q.top();
				q.pop();
			}
		}
		printf("%lld\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值