E. Yet Another Division Into Teams

首先要想明白一个东西,就是当一个小组达到六个人的时候,它一定可以拆分成两个更优的小组。

这个题可以用动态规划来写,用一个数组来保存状态,用一个队列来尝试新的状态,但是因为上面的这个特性,每一次只会有三个新的状态。

我们用sum来保存躲避选择的元素,举个例子:

分组情况为:1 2 3 | 5 6 8 11 | 20 21 22 (不一定满足题意,只是为了说明sum的意义)

sum=(5-3)+(20-11)=11

那么这样分组的总代价为:a[n]-a[1]-sum=22-1-11

那么我们的目的就是使sum尽可能的大,这样分组的代价才会尽可能的小。

另外还需要注意一点,就是三人才能成一组,所以就需要三个变量来进行一个轮回,来保证至少三人一组。

for(int i=4;i<=n;++i)
{
    pre[i]=sum.se;
    pii temp={sum.fi+a[i].fi-a[i-1].fi, i};
    sum=max(sum,t1);
    t1=t2,t2=temp;
}

代码:

// Created by CAD on 2019/11/6.
#include <bits/stdc++.h>

#define fi first
#define se second
#define pii pair<long long,int>
using namespace std;

const int maxn=2e5+5;
pii a[maxn];
int pre[maxn];
int out[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;  cin>>n;
    for(int i=1;i<=n;++i)
        cin>>a[i].fi,a[i].se=i;
    sort(a+1,a+n+1);
    pii sum={0,0},t1={0,0},t2={0,0};
    for(int i=4;i<=n;++i)
    {
        pre[i]=sum.se;
        pii temp={sum.fi+a[i].fi-a[i-1].fi, i};
        sum=max(sum,t1);
        t1=t2,t2=temp;
    }
    cout<<a[n].fi-a[1].fi-sum.fi<<" ";
    int i=sum.se;
    int v=n,cnt=0;
    while(v>0)
    {
        int u=i;
        cnt++;
        for(;u<=v;u++)
            out[a[u].se]=cnt;
        v=i-1,i=pre[i];
    }
    cout<<cnt<<endl;
    for(i=1;i<n;++i)
        cout<<out[i]<<" ";
    cout<<out[n]<<endl;
    return 0;
}