Codeforces 1256E Yet Another Division Into Teams

思路:

这题参考的自带题解的思路:

Let’s sort all students by their programming skills but save the initial indices to restore the answer.
Now we can understand that we don’t need to compose the team of size greater than 5 because in this case we can split it into more teams with fewer participants and obtain the same or even less answer.
Now we can do the standard dynamic programming dpi— the minimum total diversity of the division if we divided the first i students (in sorted order). Initially, dp0=0, all other values of dp are +∞. Because of the fact above, we can do only three transitions (0-indexed):
dpi+3=min(dpi+3,dpi+ai+2−ai);
dpi+4=min(dpi+4,dpi+ai+3−ai);
dpi+5=min(dpi+5,dpi+ai+4−ai).
The answer is dpn and we can restore it by standard carrying parent values (as a parent of the state we can use, for example, the number of participants in the team).

用这个思路去写,有一点需要注意,对dp[]进行初始化时,设定的INF应该满足1e9 < INF < INT_MAX-1e9,否则在进行计算时,会造成溢出现象;(笔者之前使用的memset(dp,127,sizeof(dp)),就出现了test10错误的现象)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> p;
#define fi first
#define sc second
#define mem(a,x) memset(a,x,sizeof(a))
#define rp(i,n) for(int i=0;i<n;i++)
#define rpn(i,n) for(int i=1;i<=n;i++)
const int MAX_N=200005;
const int INF=int(1e9) +10;
p a[MAX_N];
int dp[MAX_N];//dp[i]前i个人最小的total diversity
int t[MAX_N];
int out[MAX_N];//用于输出 
int main(){
	int n;
	scanf("%d",&n);
	rpn(i,n){
		scanf("%d",&a[i].fi);
		a[i].sc=i;
	}
	sort(a+1,a+n+1);
	fill(dp+1,dp+MAX_N,INF);
	for(int i=0;i<n;i++){
		for(int j=3;j<=5&&i+j<=n;j++){
			int diff=a[i+j].fi-a[i+1].fi;
			if(dp[i]+diff<dp[i+j]){
				dp[i+j]=dp[i]+diff;
				t[i+j]=j;//以第i+j人为结尾的队有t[i+j]人 
			}
		}
	}
	int ans=0;
	for(int i=n;i>=3;){
		ans++;//第ans队,有t[i]人 
		int num=t[i];
		while(num--) out[a[i--].sc]=ans;
	}
	printf("%d %d\n%d",dp[n],ans,out[1]);
	for(int i=2;i<=n;i++) printf(" %d",out[i]);
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值