E. Yet Another Division Into Teams dp

题目传送门


题意给你一堆数字,让你分组,每组至少三个数,每组的价值是组内最大值-最小值,问所有组值得总和最小的分组。

思路:只要你发现这个定理即可很快解决这题, 就是6个数必然有两组:

例如 a1 < a2 < ...< a6, 一组的情况 a6-a1 > 两组的情况 a6-a4+a3-a1 = a6-a1+a3-a4.. a4比a3 大所以肯定小,之后你在举例7,8个数即可 ,简单dp一下解决。

ac代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <string>
#include <cstring>
using namespace std;
const int mx = 2e5+100;
typedef long long ll;
ll dp[mx], pre[mx];
struct node {
    ll x, y, id;
}N[mx];

bool cmp(node a, node b) {
    return a.x < b.x;
}
bool cmp1(node a, node b) {
    return a.y < b.y;
}
//a6-a1+a3-a4 < a6-a1
//a7-a1+a3-a4 < a7-a1
//a7-a1+a4-a5 < a7-a1
//a8-a1+a3-a4 < a8-a1
//a8-a1+a4-a5
int main(){
    int q, n;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
        scanf("%lld", &N[i].x);
        N[i].y = i;
    }
    sort(N, N+n, cmp);
    ll now = 0, sum = 0, tot = 0;
    memset(dp, 0x3f3f3f3f3f3f3f3f, sizeof(dp));
    for (int i = 2; i < n; ++i) {
        if (i < 5) dp[i] = N[i].x-N[0].x, pre[i] = -1;
        else {
            for (int j = 2; j <= 4; ++j) {
                if (dp[i] > N[i].x-N[i-j].x+dp[i-j-1]) {
                    dp[i] = N[i].x-N[i-j].x+dp[i-j-1];
                    pre[i] = i-j-1;
                }
            }
        }
    }
    int po = n-1;
    for (int i = n-1; i >= 0; --i) {
        if (po == i) tot++, po = pre[i];
        N[i].id = tot;
    }
    printf("%lld %lld\n", dp[n-1], tot);
    sort(N, N+n, cmp1);
    for (int i = 0; i < n; ++i) {
        printf("%lld ", N[i].id);
    }
    puts("");
    return 0;
}
发布了74 篇原创文章 · 获赞 29 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/ClonH/article/details/103009785