codeforces 571B - Minimization (dp)

题意很好理解
题解 : 首先我们观察到几个事实就是说 :
1. 这 n 个数可以分成 k 段 并且这 k 段互不影响
2. 每个段内的数都是连续的数,因为只有这样,才能保证这个问题的最小性
3. 如果这 n 个数排序后每连续的两个作差取绝对值再求和答案是固定的也就是 max (a[i]) - min (a[i]) 。
4. 如果第三个是确定的并且可以保证每个段内的数都是连续的数,那我们所关心的最小值肯定就在于分段的时候的断点处的地方的两个数之差的最大值,最后用 max (a[i]) - min (a[i]) - dp[num1][num2] 就是答案了。
其中 dp[i][j] 表示长度为 len + 1 和 len 的段已经分了 i 段 和 j 段了
len = n / k;
转移就是 :
dp[i][j] = max (dp[i -1][j] + a[k + 1] - a[k],dp[i][j]);
k = (i - 1) * (len + 1) + j * len;
dp[i][j] = max (dp[i][j -1] + a[k + 1] - a[k],dp[i][j]);
k = i * (len + 1) + (j - 1) * len;
这样就 ok 了

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 5005;
const int INF = 1E9 + 7;
int n,k;
int dp[maxn][maxn] = {0};
int a[300005] = {0};
int num1,num2;
int main () {
    ios_base :: sync_with_stdio(false);
    cin >> n >> k;
    for (int i = 1;i <= n; ++ i) {
        cin >> a[i];
    }
    sort (a + 1,a + n + 1);
    num1 = n % k;
    num2 = k - n % k;
    int len = n / k;
    for (int i = 0;i <= k + 1; ++ i) {
        for (int j = 0;j <= k + 1; ++ j) dp[i][j] = -INF;
    }
    dp[1][0] = dp[0][1] = 0;
    for (int i = 0;i <= num1; ++ i) {
        for (int j = 0;j <= num2; ++ j) {
            if (i) {
                int k = (len + 1) * (i - 1) + j * len;
                dp[i][j] = max (dp[i][j],dp[i - 1][j] + a[k + 1] - a[k]);
            }
            if (j) {
                int k = (len + 1) * i + len * (j - 1);
                dp[i][j] = max (dp[i][j],dp[i][j - 1] + a[k + 1] - a[k]);
            }
        }
    }
    int ans = a[n] - a[1] - dp[num1][num2];
    cout << ans << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值