题目大意
给出 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
n−x−y 表所有m[i] 小于i的人的个数
n − x − y + x n-x-y+x n−x−y+x 就表示我目前已经有的前缀和已经收买的人的总和
n − y ≥ m [ i ] n-y \ge m[i] n−y≥m[i]的时候 自然就会免费投票
否则 n − y ≤ m [ i ] n-y \le m[i] n−y≤m[i] 也就是说 y ≥ n − m [ i ] y \ge n-m[i] y≥n−m[i] 时,我们需要收买几个人 使得第i个人能够给我投票。那么我只需要收买 这y个人中 p [ i ] p[i] p[i] 最小的 ( y − ( n − m [ i ] ) ) (y-(n-m[i])) (y−(n−m[i])) 个人即可
优先队列维护一下
#include <bits/stdc++.h>
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;
}