题意
给你n个人,你需要让这n个人全部给你投票。让第i个人给你投票的方法有两种:给他pi块钱收买他,或者当前已经有mi个人为你投票,他就会为你免费投票。问最少花费多少钱
思路
首先不难发现,这道题可以贪心,在m相等的人里优先给花费少的人钱。又因为,如果我们让某个m=i的人可以免费为我们投票,则m<=i的其他人,都可以免费给我们投票。所以我们可以从大到小枚举m,设为M,更新ans,使得mi=M时,ans为m>=M的人都已经为我们投票时的最小花费。所以问题就转换为了如何更新ans。
注意我们这个枚举有一个前提,就是对于每一个M取值,我们都假设了对于m<M的人,我们都已经获得了他的选票,只不过这个ans的值没有更新。所以对于每一个M的取值,我们设m=M的人数为x,m>M中,我们打算白嫖的人的人数为y,那么根据假设,我们现在已经获得了n-y个人的选票。那么这x个人中,我们最多也可以白嫖n-y-M个人,那么x中剩下的人,我们就需要去买。用优先队列记录一下,把p最小的那些人买了,ans就更新完成了。
代码
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define rush() int TT;scanf("%d",&TT);for(int TTT=1;TTT<=TT;TTT++)
const int maxn = 2e5+5;
vector<int> v[maxn];
int main() {
rush() {
int n,m,p;
cin>>n;
for(int i=0; i<=n; i++)
v[i].clear();
for(int i=0; i<n; i++) {
cin>>m>>p;
v[m].push_back(p);
}
priority_queue<int, vector<int>, greater<int>> q;
ll ans = 0;
for(int i=n-1; i>=1; i--) {
for(int j=0; j<v[i].size(); j++)
q.push(v[i][j]);
while(q.size()>n-i) {
ans+=q.top();
q.pop();
}
}
cout<<ans<<endl;
}
return 0;
}