CodeForces 1019A Elections|贪心

题目链接
题目大意:
因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;
}
原文地址:https://www.cnblogs.com/fmj123/p/14274676.html