CodeForces 1019A Elections|贪心

题目链接
题目大意:
因zz不正确做了特殊处理

\(n\)voter\(m\)Party。每个voter会投给一个Party\(p_i\),同时,若给\(c_i\)money,则会投给你指定的某个Party,现在给出每个voter的情况,求\(1\)Party要赢需要给voter共多少钱。一个Party要胜利当且仅当其获得票数比其他都要多。

\(1\le n,m\le 3000\)

题目思路:

本题难点在于,改选后得票最大这一称号可能易主。这同时导致了收拢\(c_i\)最小的人的贪心策略不正确。

那么我们需要规避这个问题。一个灵光一闪的想法是枚举其他Party最大得票数,若超过则按\(c_i\)由小到大砍掉多余票数。显然,此时\(1\)Party需要比最大得票数多\(1\),如果砍完票数后不满足条件,则从\(p_i \neq 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;
}
posted @ 2021-01-15 20:14  fmj_123  阅读(93)  评论(0编辑  收藏  举报