B. Minimization
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
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
![](https://i-blog.csdnimg.cn/blog_migrate/75371a3232fd45e1700b4ddd6f015698.png)
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.
Examples
input
3 2 1 2 4
output
1
input
5 2 3 -5 3 -5 3
output
0
input
6 3 4 3 4 3 2 5
output
3
Note
In the first test one of the optimal permutations is 1 4 2.
In the second test the initial order is optimal.
In the third test one of the optimal permutations is 2 3 4 4 3 5.
题目大意:你有一个数列,要重新排列,使得相隔k位的数的差的绝对值之和最小。
思路:本题可以采用分段,可以看出,1——k之间的任何一个数都是互不干扰,且1——k之间的每一个数都带领着一个数链,故可以在排序后DP,设置状态为:f[i][j]表示有i段长链和j段短链所获得的最小值(因为有可能无法均分所以链有长短之分,长短链的长度相差1)。转移:f[i][j]可以向f[i+1][j]和f[i][j+1]转移。
附代码。
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdlib>
using namespace std;
const int MAXN=300010;
const int MAXK=5010;
const long long INF=20000000000;
long long f[MAXK][MAXK];
int a[MAXN];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int len,lnum,snum;
len=n/k;
lnum=n%k;
snum=k-lnum;
for (int i=0;i<=snum;i++)
{
for (int j=0;j<=lnum;j++)
{
f[i][j]=INF;
}
}
f[0][0]=0;
for (int i=0;i<=snum;i++)
{
for (int j=0;j<=lnum;j++)
{
int pos=i*len+j*(len+1)+1;
if (i!=snum)
{
f[i+1][j]=min(f[i+1][j],f[i][j]+a[pos+len-1]-a[pos]);
}
if (j!=lnum)
{
f[i][j+1]=min(f[i][j+1],f[i][j]+a[pos+len]-a[pos]);
}
}
}
cout<<f[snum][lnum];
return 0;
}