codeforces1251E2 Voting【优先队列+思维】

题目大意

给出 n n n 个人,每个人两个值 m [ i ] m[i] m[i], p [ i ] p[i] p[i] p [ i ] p[i] p[i] 表示 收买这个人给你投票需要的花费 , m [ i ] m[i] m[i]表示,如果已经有 m [ i ] m[i] m[i]个人给你投票, 第 i i i个人就会免费给你投票。

题目思考

这个题是一个比较强的思维题。

首先我们一定可以知道以下几个关系:

1、如果我能够让第i个人免费给我投票的话,那么 所有m[i] 小于i的人,一定也可以免费给我投票。

那么我们就可以考虑,按照m从大到小收买.
这样我们可以得到下面这个条件

2、如果说,现在第i个人不能免费给我投票了的话,说明权值大于m[i]的人一定全部被我收买了。

假设访问到第i个人。
我假设我已经收买的人的有 x x x 个, 目前还未被收买的人有 y y y
n − x − y n-x-y nxy 表所有m[i] 小于i的人的个数

n − x − y + x n-x-y+x nxy+x 就表示我目前已经有的前缀和已经收买的人的总和

n − y ≥ m [ i ] n-y \ge m[i] nym[i]的时候 自然就会免费投票

否则 n − y ≤ m [ i ] n-y \le m[i] nym[i] 也就是说 y ≥ n − m [ i ] y \ge n-m[i] ynm[i] 时,我们需要收买几个人 使得第i个人能够给我投票。那么我只需要收买 这y个人中 p [ i ] p[i] p[i] 最小的 ( y − ( n − m [ i ] ) ) (y-(n-m[i])) (y(nm[i])) 个人即可

优先队列维护一下

#include 
using namespace std;
const int maxn =2e5+50;
typedef long long ll;
vector<ll>v[maxn];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		for(int i=0;i<=n;i++) v[i].clear();
		for(int i=1;i<=n;i++)
		{
				int m;ll p;
				cin>>m>>p;
				v[m].push_back(p);
		}	
		priority_queue<ll,vector<ll>,greater<ll> > pq;
		ll ans =0;
		for(int i=n-1;i>=0;i--)
		{
			for(int j=0;j<v[i].size();j++)
			{
				pq.push(v[i][j]);
			}
			while(pq.size()>n-i)
			{
				ans += pq.top();
				pq.pop();
			}
		}
		cout<<ans<<endl;
	}
	
	
	return 0;
}

你可能感兴趣的:(数据结构,脑洞)