题意:有 n 个投票人和 m 个竞选者,每个投票人都有初始想投的人(编号从1到m),然而,你可以花费一定代价让一个投票人改变选择,让他投给你指定的人,现在为了保证1号竞选者竞选的成功,它的得票数必须超过其余任何人,求最少需要的代价;
分析:n,m<=3000,数据范围比较小,考虑枚举 1 号最终的得票数,我们按照改变每个投票人选择的代价从小到大排序,并且枚举 1 号最终的得票数 k ,则其余竞选人的初始得票数若大于等于k ,则必然要改变他们的选择,让他们的得票数统统小于k;
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
typedef pair<int,int> P;
const int N = 3005;
#define x first
#define y second
P p[N];
int n,m;
int tim[N];
int ned[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&p[i].y,&p[i].x);
tim[p[i].y]++;
}
sort(p+1,p+n+1);
ll ans;
if(tim[1]<=n/2+1) ans=1e17; //若初始得票数就大于一半,代价就是0
else ans=0;
for(int t=tim[1];t<=n/2+1;t++)
{
ll sum=0,add=0;
for(int i=2;i<=m;i++)
{
if(tim[i]>=t) ned[i]=tim[i]-t+1,add+=ned[i]; //表示至少需要改变多少初始选择为 i的投票人才能满足条件;
else ned[i]=0;
}
if(add>t-tim[1]) continue; //如果改变所有初始得票过多的人的数量已经大于当前枚举的1号得票数需要增加的数量就跳过;
int left=t-tim[1]-add;
for(int i=1;i<=n;i++)
{
if(p[i].y==1) continue;
if(ned[p[i].y]==0)
{
if(left)
{
left--;
sum+=p[i].x;
}
}
else
{
ned[p[i].y]--;
sum+=p[i].x;
}
}
ans=min(ans,sum);
}
printf("%lld",ans);
}