CF1256E Yet Another Division Into Teams(动态规划)

题意:

你们大学有n个学生。第i个学生的编程技巧是人工智能。作为教练,你要把他们分成几个小组,为即将到来的ICPC决赛做准备。想象一下,如果这所大学有2⋅105名学生准备进入期末考试,那该有多好!

每队至少由三名学生组成。每个学生应该属于一个团队。团队的多样性是属于该团队的某个学生的最大编程技能与属于该团队的某个学生的最小编程技能之间的差异(换句话说,如果团队由具有编程技能a[i1]、a[i2]、…、a[ik]的k个学生组成,那么这个团队的多样性是maxj=1ka[ij]——minj=1ka[ij])。

总的多样性是组成的所有团队多样性的总和。

你的任务是最大限度地减少学生划分的多样性,并找到最佳的方法来划分学生。

输入

输入的第一行包含一个整数n(3≤n≤2⋅105)-学生人数。

输入的第二行包含n个整数a1,a2,…,an(1≤ai≤109),其中ai是第i个学生的编程技能。

输出

在第一行中,打印两个整数res和k-相应地,学生分组的最小总多样性和所在分组的队数。

在第二行中,打印n个整数t1,t2,…,tn(1≤ti≤k),其中ti是第i个学生所属的团队的数量。

如果有多个答案,您可以打印任何答案。注意,您不需要最小化团队的数量。每队至少由三名学生组成。

/*
 * cf1256E
 * 题意:
 * 给你n个数字,划分成若干队伍,每个队伍都有一个最大最小值的差值,如何划分才能使得所有队伍的最大最小差值之和最小
 * 首先推导一个结论:一个队伍最多有5个人。因为如果有六个人的话,分成两个3人分组是更优的
 * 动态规划处理:
 * 用dp[i]表示前i个数字(已经排序过的)所分的组的差异之和
 * 令d表示划分长度,从i位置开始往前分
 * dp[i]=min(dp[i],dp[i-d]+a[c[i]]-a[c[i-d+1]])
 */
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+100;
int N;
ll a[maxn];//保存原始数据
int b[maxn];//保存划分方法
int c[maxn];//保存排序后第i名在a数组中的下标
ll dp[maxn];//表示前i个数字的最小差异总数
int cmp (int x,int y) {
    return a[x]<a[y];
}
int main () {
    scanf("%d",&N);
    for (int i=1;i<=N;i++) scanf("%lld",&a[i]);
    for (int i=1;i<=N;i++) c[i]=i;
    sort(c+1,c+N+1,cmp);
    for (int i=1;i<=N;i++) {
        dp[i]=1e18;
        for (int j=3;j<=min(5,i);j++) {
            //最多五个连续的数相连
            dp[i]=min(dp[i],dp[i-j]+a[c[i]]-a[c[i-j+1]]);
        }
    }
    int ans=0;
    for (int i=N;i;) {
        for (int j=3;j<=min(5,i);j++)
            if (dp[i]==dp[i-j]+a[c[i]]-a[c[i-j+1]]) {
                ++ans;
                for (int k=1;k<=j;k++) b[c[i-k+1]]=ans;
                i-=j;
                break;
            }
    }
    printf("%lld %d\n",dp[N],ans);
    for (int i=1;i<=N;i++) printf("%d ",b[i]);
}

猜你喜欢

转载自www.cnblogs.com/zhanglichen/p/12822704.html