codeforces 1256E Yet Another Division Into Teams

傳送門

題意:

n個數字,分成若干隊伍(每個隊伍至少3個數字),每個隊伍都有最大最小值的差值,如何才能使所有隊伍的最大最小差值之和最小。

題解:

容易有結論:人數 \geq6,一定沒有,人數<6優

下證:不妨設 \max(P[i])=A\quad\min(p[i])=B

           則任取 C,D(\not =A,B)\in P[i]\quad(C>D)

           有 A-C+B-D<A-B

所以我們可以通過將所有隊員劃分爲3、4、5人數的隊伍,貪心得按照大小順序選擇隊員一定優,然後通過dp劃分即可得到最優解

至於舉例即可從後往前倒退dp最優解得出,原因是,最優解確定即可從後往前判斷是否從當前得到的最優解,即能推出最優劃分情況

代碼:

#include"algorithm"
#include"iostream"
#include"stdlib.h"
#include"string.h"
#include"stdio.h"
#define ll long long
using namespace std;
const int Maxn=200005;
struct node
{
	ll sk,num;
}p[Maxn];
ll f1[Maxn];
int f2[Maxn],ans[Maxn];
inline bool cmp1(node a,node b)
{
	return a.sk<b.sk;
}
int main()
{
//	freopen("text.in","r",stdin);
	memset(f1,999999,sizeof(f1));
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&p[i].sk),p[i].num=i;
	sort(p+1,p+n+1,cmp1);
	f1[3]=p[3].sk-p[1].sk;
	f1[4]=p[4].sk-p[1].sk;
	f1[5]=p[5].sk-p[1].sk;
	f2[1]=f2[2]=f2[3]=f2[4]=f2[5]=1;
	for(int i=6;i<=n;i++)
	{
		for(int j=2;j<=4;j++)
			if(i-j-1>=3&&f1[i-j-1]+p[i].sk-p[i-j].sk<f1[i])
			{
				f1[i]=f1[i-j-1]+p[i].sk-p[i-j].sk;
				f2[i]=f2[i-j-1]+1;
			}
	}
	int cnt=0;
	for(int i=n;i;)
	{
		if(f2[i]==1)ans[p[i].num]=cnt+1,i--;
		for(int j=3;j<=min(5,i);j++)
		if(f1[i]==f1[i-j]+p[i].sk-p[i-j+1].sk)
		{
			cnt++;
			for(int k=j-1;k>=0;k--)
				ans[p[i-k].num]=cnt;
			i=i-j;
			break;
		}
	}
	printf("%lld %d\n",f1[n],f2[n]);
	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章