codeforces 317 B. Minimization


题目描述:

You’ve got array A, consisting of n integers and a positive integer k. Array A is indexed by integers from 1 to n.

You need to permute the array elements so that value
(就是错k个相减)

became minimal possible. In particular, it is allowed not to change order of elements at all.

Input

The first line contains two integers n, k (2 ≤ n ≤ 3·105, 1 ≤ k ≤ min(5000, n - 1)).

The second line contains n integers A[1], A[2], …, A[n] ( - 109 ≤ A[i] ≤ 109), separate by spaces — elements of the array A.

Output

Print the minimum possible value of the sum described in the statement.

题解:

很好的一道题.性质要一直往前想.
首先,我们很容易发现分组成k组之后k组之间就没关系了
其次,k组内部怎么好呢?如果都是一样的就好了,一样的不够了,就用最接近的。关键来了,一组内一定要是整体升序(当然降序也。。不妨),这个性质来的很关键,并且我们是想要挨着越近越好。所以就是连续的一段升序。那么一共有k组,我们给谁呢?
最后,现在我们知道了先把a升序排个序,然后一段一段的挑出来,要连续挑出k段,一个长n/k,一个长n/k+1,我们之后dp【i】【j】,表示有i个第一类型,j个第二类型。o(1)转移。

重点:

(1)性质的感觉+猜测。 想要什么就假设什么然后观察相近的。 记住排序,连续则写贪心点。
(2)dp的工具使用

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 3e5+100;
const int maxK = 5000+10;
const ll INF = 1e18;
int a[maxn], n, k;
ll f[maxK][maxK];
ll gao(int i, int j, int len)
{
    int s = i*(n/k)+j*(n/k+1)+1;
    int t = s+len-1;
    return a[t]-a[s];
}
void solve()
{
    sort(a+1, a+1+n);
    int ni = k - n%k;//n/k
    int nj = n%k;//n/k+1
    f[0][0] = 0;
    for(int i = 0;i<=ni;i++)
    {
        for(int j = 0;j<=nj;j++)
        {
            if(i==0&&j==0)
                continue;
            f[i][j] = INF;
            if(i>=1)
            {
                f[i][j] = min(f[i][j], f[i-1][j]+gao(i-1, j, n/k));
            }
            if(j>=1)
            {
                f[i][j] = min(f[i][j], f[i][j-1]+gao(i, j-1, n/k+1));
            }
        }
    }
    printf("%I64d\n", f[ni][nj]);
}

int main()
{
    freopen("2Bin.txt", "r", stdin);
    //freopen("3Bout.txt", "w", stdout);
    while(scanf("%d%d", &n, &k)!=EOF)
    {
        for(int i = 1;i<=n;i++)
            scanf("%d", &a[i]);
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值