E. Yet Another Division Into Teams(Codeforces Round #598 (Div. 3))(划分数-贪心-模拟)

E. Yet Another Division Into Teams(Codeforces Round #598 (Div. 3))(划分数-贪心-模拟)

time limit per test:2 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

Description

There are n n students at your university. The programming skill of the i i -th student is a i a_i . As a coach, you want to divide them into teams to prepare them for the upcoming ICPC finals. Just imagine how good this university is if it has 2 1 0 5 2⋅10^5 students ready for the finals!

Each team should consist of at least three students. Each student should belong to exactly one team. The diversity of a team is the difference between the maximum programming skill of some student that belongs to this team and the minimum programming skill of some student that belongs to this team (in other words, if the team consists of k students with programming skills a [ i 1 ] , a [ i 2 ] , , a [ i k ] a[i1],a[i2],…,a[ik] , then the diversity of this team is m a x j = 1 k a [ i j ] m i n j = 1 k a [ i j ] ) max_{j=1}^{k}a[i_j]−min_{j=1}^{k}a[i_j]) .

The total diversity is the sum of diversities of all teams formed.

Your task is to minimize the total diversity of the division of students and find the optimal way to divide the students.

Input

The first line of the input contains one integer n ( 3 n 2 105 ) n (3≤n≤2⋅105) — the number of students.

The second line of the input contains n n integers a 1 , a 2 , , a n ( 1 a i 1 0 9 ) a_1,a_2,…,a_n (1≤a_i≤10^9) , where a i a_i is the programming skill of the i i -th student.

Output

In the first line print two integers r e s res and k k — the minimum total diversity of the division of students and the number of teams in your division, correspondingly.

In the second line print n n integers t 1 , t 2 , , t n ( 1 t i k ) t_1,t_2,…,t_n (1≤t_i≤k) , where t i t_i is the number of team to which the i i -th student belong.

If there are multiple answers, you can print any. Note that you don’t need to minimize the number of teams. Each team should consist of at least three students.

input

5
1 1 3 4 2

output

3 1
1 1 1 1 1 

input

6
1 5 12 13 2 15

output

7 2
2 2 1 1 2 1 

input

10
1 2 5 129 185 581 1041 1909 1580 8150

output

7486 3
3 3 3 2 2 2 2 1 1 1 

Note

In the first example, there is only one team with skills [ 1 , 1 , 2 , 3 , 4 ] [1,1,2,3,4] so the answer is 3 3 . It can be shown that you cannot achieve a better answer.

In the second example, there are two teams with skills [ 1 , 2 , 5 ] [1,2,5] and [ 12 , 13 , 15 ] [12,13,15] so the answer is 4 + 3 = 7 4+3=7 .

In the third example, there are three teams with skills [ 1 , 2 , 5 ] [1,2,5] , [ 129 , 185 , 581 , 1041 ] [129,185,581,1041] and [ 1580 , 1909 , 8150 ] [1580,1909,8150] so the answer is 4 + 912 + 6570 = 7486 4+912+6570=7486 .

题意

给你 n n 个数字,分成若干队伍,每个队伍都有最大最小值的差值,如何划分才能使所有队伍的最大最小差值之和最小。

首先推导出一个结论:每个队伍最多有 5 5 个人,因为一旦有 6 6 个人的话,那么分成两个 3 3 人组显然更优。

那么就利用动态规划的思想贪心地比较所有的分法:
d p [ i ] dp[i] 表示前 i i 个数字(已经排序过的)所分的组的差异之和。
d d 为划分长度,从 i i 位置往前划分

那么就有
d p [ i ] = m i n ( d p [ i ] , d p [ i d ] + a [ c [ i ] ] a [ c [ i d + 1 ] ] ) dp[i] = min(dp[i], dp[i - d] + a[c[i]] - a[c[i - d + 1]])

意思就是比较 d d 分别为 3 4 5 3,4,5 时,取前 i i 项数字的划分的差异数的最小值。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXA = 3e5;
int n, N, b[MAXA]/*保存划分方法*/, c[MAXA]/*保存排序后第i名在a数组中的下标*/;
long long dp[MAXA]/*表示前i个数字的最小差异总数*/, a[MAXA]/*保存原始数据*/;
int mysort(int x, int y) {
	return a[x] < a[y];
}
int main() {
	//freopen("in.txt", "r", stdin);
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%I64d", &a[i]), c[i] = i;
	sort(c + 1, c + n + 1, mysort);	/*按大小排序-保留映射*/
	for (int i = 1; i <= n; i++) {
		dp[i] = 1e18;
		for (int d = 3; d <= min(5, i)/*最多是5个连续的数相连接,如果有长度为6的那么划分成两个长度为3的肯定更优*/; d++) {
			/*d代表划分的长度,取值范围是3-5,代表从i往前d个分在一起*/
			dp[i] = min(dp[i], dp[i - d] + a[c[i]] - a[c[i - d + 1]]);	/*贪心地选择差异总数更小的划分*/
		}
	}
	for (int i = n; i;) {
		for (int d = 3; d <= min(5, i); d++)
			if (dp[i] == dp[i - d] + a[c[i]] - a[c[i - d + 1]]) {	/*如果当前的划分符合之前找出来的最优划分,就按照这样划分*/
				++N;
				for (int k = 1; k <= d; k++) b[c[i - k + 1]] = N;	/*保存此划分*/
				i = i - d;
				break;
			}
	}
	printf("%I64d %d\n", dp[n], N);
	for (int i = 1; i <= n; i++) printf("%d ", b[i]);
}

/*
in:
9
6 6 6 10 15 15 19 19 19

out:
5 3
3 3 3 2 2 2 1 1 1

in:
6
1 2 2 2 3 4

out:
3 2
2 2 2 1 1 1
*/

发布了163 篇原创文章 · 获赞 54 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_42856843/article/details/102965034