现在你要竞选一个县的县长。你去对每一个选民进行了调查。你已经知道每一个人要选的人是谁,以及要花多少钱才能让这个人选你。现在你想要花最少的钱使得你当上县长。你当选的条件是你的票数比任何一个其它候选人的多(严格的多,不能和他们中最多的相等)。请计算一下最少要花多少钱。
Input
单组测试数据。
第一行有一个整数n (1 ≤ n ≤ 10^5),表示这个县的选民数目。
接下来有n行,每一行有两个整数ai 和 bi (0 ≤ ai ≤ 10^5; 0 ≤ bi ≤ 10^4),表示第i个选民选的是第ai号候选人,想要让他选择自己就要花bi的钱。你是0号候选人(所以,如果一个选民选你的话ai就是0,这个时候bi也肯定是0)。
Output
输出一个整数表示花费的最少的钱。
Input示例
5
1 2
1 2
1 2
2 1
0 0
Output示例
3
思路:
将每个候选人的选票金额从大到小排序。开始时假定购买所有选票,然后依次尝试放弃选票,比如除自己外有三个候选人。则第一轮尝试放弃这三个候选人的各自的最大选票金额,第二轮尝试放弃这三个候选人的第二大选票金额,依次累进。在每次放弃时,将放弃的选票金额放进线段树。在每轮放弃后,要判断是否满足当选条件,如果不满足,比如差a张选票,则需要从线段树中找到最小的a个算出总代价。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXA = 1e5 + 10;
const int MAXB = 1e4 + 10;
#define lson (root << 1)
#define rson (root << 1 | 1)
struct Node
{
int val;
int num;
};
int n;
Node tree[MAXB << 2];
vector<int> cost[MAXA];
vector<int> buf[MAXA];
void update(int root, int left, int right, int x)
{
if (left == right)
{
tree[root].val += left;
tree[root].num += 1;
return;
}
int mid = left + (right - left) / 2;
if (x <= mid)
{
update(lson, left, mid, x);
}
else
{
update(rson, mid + 1, right, x);
}
tree[root].val = tree[lson].val + tree[rson].val;
tree[root].num = tree[lson].num + tree[rson].num;
}
int query(int root, int left, int right, int count)
{
if (left == right)
{
return count * left;
}
int mid = left + (right - left) / 2;
if (count <= tree[lson].num)
{
return query(lson, left, mid, count);
}
else
{
return tree[lson].val + query(rson, mid + 1, right, count - tree[lson].num);
}
}
int main()
{
cin >> n;
int ans = 0, mx_num = 0, mx_cost = 1, a, b;
for (int i = 1; i <= n; i++)
{
cin >> a >> b;
if (b == 0)
{
continue;
}
ans += b;
mx_num = max(mx_num, a);
mx_cost = max(mx_cost, b);
cost[a].push_back(b);
}
int mx_size = 0;
for (int i = 1; i <= mx_num; i++)
{
if (cost[i].size())
{
sort(cost[i].begin(), cost[i].end(), greater<int>());
mx_size = max(mx_size, (int)cost[i].size());
for (int j = 0; j < cost[i].size(); j++)
{
buf[j].push_back(cost[i][j]);
}
}
}
int k = n, res = ans;
for (int i = 0; i < mx_size; i++)
{
k -= buf[i].size();
for (int j = 0; j < buf[i].size(); j++)
{
update(1, 1, mx_cost, buf[i][j]);
res -= buf[i][j];
}
int tmp = 0, mn;
if (k <= i + 1)
{
mn = min(i + 2 - k, n);
tmp = query(1, 1, mx_cost, mn);
}
ans = min(ans, res + tmp);
}
cout << ans << endl;
return 0;
}