题目链接
题目大意:
因zz不正确做了特殊处理
(n)个voter
,(m)个Party
。每个voter
会投给一个Party
(p_i),同时,若给(c_i)money
,则会投给你指定的某个Party
,现在给出每个voter
的情况,求(1)号Party
要赢需要给voter
共多少钱。一个Party
要胜利当且仅当其获得票数比其他都要多。
(1le n,mle 3000)
题目思路:
本题难点在于,改选后得票最大这一称号可能易主。这同时导致了收拢(c_i)最小的人的贪心策略不正确。
那么我们需要规避这个问题。一个灵光一闪的想法是枚举其他Party
最大得票数,若超过则按(c_i)由小到大砍掉多余票数。显然,此时(1)号Party
需要比最大得票数多(1),如果砍完票数后不满足条件,则从(p_i
eq 1)的未被选择的(i)中选择(c_i)最少的voter
直到票数满足要求。
本题的(n m)规模较小,因此枚举即可。时间复杂度(O(n^2logn))
上代码
#include<bits/stdc++.h>
using namespace std;
int n,m,cnt[3010],net[3010],fr[3010];bool vis[3010];
struct voter
{
int p;long long c;
}a[5000];
bool cmp(voter x,voter y)
{
return x.c>y.c;
}
int main()
{
cin>>n>>m;
for (int i=1;i<=n;i++)
{
cin>>a[i].p>>a[i].c;
}
sort(a+1,a+n+1,cmp);
int maxx=0;
for (int i=1;i<=n;i++)
{
cnt[a[i].p]++;maxx=max(maxx,cnt[a[i].p]);
net[i]=fr[a[i].p];fr[a[i].p]=i;
}
long long ans=3000*1e9;
for (int i=maxx;i>=0;i--)
{
int l=i+1-cnt[1];long long s=0;
for (int j=1;j<=n;j++) vis[j]=false;
for (int j=2;j<=m;j++)
{
if (cnt[j]>i)
{
int tmp=cnt[j];
for (int k=fr[j];k;k=net[k])
{
s+=a[k].c;vis[k]=true;
tmp--;l--;
if (tmp==i) break;
}
}
}
for (int j=n;l>0&&j>0;j--)
{
if (a[j].p!=1&&!vis[j])
{
vis[j]=true;
s+=a[j].c;
l--;
}
}
if (l<=0) ans=min(ans,s);
}
cout<<ans<<endl;
return 0;
}