CF1256E Yet Another Division Into Teams

題目傳送門

題面

你有 n n n個選手,每個選手都有一個勢力值,你要把他們分成多個小組,每個小組最少要有3個人,每個小組的多樣性值為勢力值最大值減去最小值,問讓你提出一種分組方式使得多樣性總和最小。

解題方法

我們發現組分的越多,答案一定越小,所以說我們發現每個小組的人數一定是 3 − 5 3-5 35人,然后我們就可以通過 d p dp dp求答案了,我們能夠發現的遞推式如下:
d p [ i + 3 ] = m i n ( d p [ i + 3 ] , d p [ i ] + a [ i + 2 ] − a [ i ] ) ; d p [ i + 4 ] = m i n ( d p [ i + 4 ] , d p [ i ] + a [ i + 3 ] − a [ i ] ) ; d p [ i + 5 ] = m i n ( d p [ i + 5 ] , d p [ i ] + a [ i + 4 ] − a [ i ] ) ; dp[i+3]=min(dp[i+3],dp[i]+a[i+2]-a[i]);\\ dp[i+4]=min(dp[i+4],dp[i]+a[i+3]-a[i]);\\ dp[i+5]=min(dp[i+5],dp[i]+a[i+4]-a[i]); dp[i+3]=min(dp[i+3],dp[i]+a[i+2]a[i]);dp[i+4]=min(dp[i+4],dp[i]+a[i+3]a[i]);dp[i+5]=min(dp[i+5],dp[i]+a[i+4]a[i]);
然後就可以求出答案了。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
	int v,pos;
}a[200100];
bool comp(node x,node y)
{
	return x.v<y.v;
}
int dp[200100];
int minn[200100];
int z[200100];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	  scanf("%d",&a[i].v),a[i].pos=i;
	sort(a+1,a+n+1,comp);
	for(int i=2;i<=n+1;i++)
	{
		minn[i]=-1;
		dp[i]=9e8+7; 
	} 
	for(int i=1;i<=n;i++)
	{
		if(i+3<=n+1)
			if(dp[i+3]>dp[i]+a[i+2].v-a[i].v)  dp[i+3]=dp[i]+a[i+2].v-a[i].v,minn[i+3]=i ;
		if(i+4<=n+1)
			if(dp[i+4]>dp[i]+a[i+3].v-a[i].v) dp[i+4]=dp[i]+a[i+3].v-a[i].v,minn[i+4]=i; 
		if(i+5<=n+1)
			if(dp[i+5]>dp[i]+a[i+4].v-a[i].v) dp[i+5]=dp[i]+a[i+4].v-a[i].v,minn[i+5]=i; 
	}
	int tot=0; 
	int now=n+1;
	while(now!=1)
	{
		for(int i=now-1;i>=minn[now];i--)
		  z[a[i].pos]=tot;
		tot++;
		now=minn[now];
	}
	cout<<dp[n+1]<<' '<<tot<<'\n';
	for(int i=1;i<=n;i++)
	  cout<<z[i]+1<<' ';
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值