CF457C Elections
题目描述
You are running for a governor in a small city in Russia. You ran some polls and did some research, and for every person in the city you know whom he will vote for, and how much it will cost to bribe that person to vote for you instead of whomever he wants to vote for right now. You are curious, what is the smallest amount of money you need to spend on bribing to win the elections. To win elections you need to have strictly more votes than any other candidate.
输入格式
First line contains one integer nn ( 1<=n<=10^{5}1<=n<=105 ) — number of voters in the city. Each of the next nn lines describes one voter and contains two integers a_{i}a**i and b_{i}b**i ( 0<=a_{i}<=10^{5}; 0<=b_{i}<=10^{4}0<=a**i<=105; 0<=b**i<=104 ) — number of the candidate that voter is going to vote for and amount of money you need to pay him to change his mind. You are the candidate 00 (so if a voter wants to vote for you, a_{i}a**i is equal to zero, in which case b_{i}b**i will also be equal to zero).
输出格式
Print one integer — smallest amount of money you need to spend to win the elections.
题解:
一眼看出来贪心。
是CF1019A的加强版。
CF1019A是N^2贪心就能过,这个必须加二分枚举。
当然,贪心策略都是一样的。
咋贪呢?发现如果正向考虑买票,并不是买价格最小的选民就最优,因为其他党派比你票多,如果你在削弱大党的同时给自己买票,有可能会更优。
所以考虑逆向贪心。
直接枚举自己最终胜选的票数是多少票,假设是(x)张。然后显然,高于这些票数的党派都需要被砍成(x-1)张才能保证让联合党胜出。在砍这些党派的过程中,肯定要从小到大买。
在砍完这些党派之后,如果1党还是没有等于x,那只好从剩下的所有党派中从小到大买。
然后发现这整个算法流程就是一二分判断。
代码:
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=3003;
int n,m;
vector<int> v[maxn];
ll check(int x)//买x张选票能否更优
{
ll ret=0;
int tot=0;
vector<int> tmp;
for(int i=1;i<=m;++i)
{
int j=0,k=v[i].size();
while(k>=x)
ret+=v[i][j++],--k,++tot;
while(j<v[i].size())
tmp.push_back(v[i][j++]);
}
sort(tmp.begin(),tmp.end());
for(int i=0;i<tmp.size();++i)
{
if(tot>=x)
break;
ret+=tmp[i],++tot;
}
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int p,c;
scanf("%d%d",&p,&c);
v[p].push_back(c);
}
for(int i=1;i<=m;i++)
sort(v[i].begin(),v[i].end());
for(int i=0;i<v[1].size();i++)
v[1][i]=0;
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)<check(mid+1))
r=mid-1;
else
l=mid+1;
}
printf("%lld
",check(l));
return 0;
}