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
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.
Print the minimum possible value of the sum described in the statement.
3 2 1 2 4
1
5 2 3 -5 3 -5 3
0
6 3 4 3 4 3 2 5
3
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.
题目链接http://codeforces.com/contest/572/problem/D
计算|arr[1]-arr[k+1]|+|arr[2]-arr[k+2]|+......+|arr[n-k]-arr[n]|,不妨将前式转换为
|arr[1]-arr[k+1]|+|arr[k+1]-arr[k+1+k]|+|arr[k+1+k]-arr[k+1+k+k]|+.....(其中k+1+k+...+k<=数组元素的个数n)
+|arr[2]-arr[k+2]|+|arr[k+2]-arr[k+2+k]|+|arr[k+2+k]-arr[k+2+k+k]|+....(其中k+2+k+...+k<=数组元素的个数n)
+......
+|arr[k]-arr[k+k]|+|arr[k+k]-arr[k+k+k]|+|arr[k+k+k]-arr[k+k+k+k]|+....(其中k+k+k+...+k<=数组元素的个数n)
这样分成了以1,2....k开头的k组;每组的长度可能是n/k或者n/k+1;
长度为n/k+1的组数为n%k;长度为n/k的组数为k-n%k;
只有每组的元素都是有序的,每组的相邻元素的差的和才会最小;
若每组元素都是有序的,则上面k组的结果就分别等价于:
|arr[1]-arr[k+1+k+.....+k]| ,|arr[2]-arr[k+2+k+...k]| , ....... ,|arr[k]-arr[k+k+k+...k]|;
这样每组的和只与这一组的第一个元素和最后一个元素有关; 类似于((a1-a2)+(a2-a3)+...+(a[n-1]-a[n]))=a1-a[n];
最终结果就是这k组的和;
所以现在的问题就是这k组中n%k个较长的组和k-n%k个较短的组怎么选;
比如第二组数据 -5,-5,3,3,3 ;其中长组的个数为1,短组的个数为1;段组的长度为2;长组的长度为3;
先对数据排序,如果选-5,-5,3为一组(长组),3,3为一组(短组);那么最后结果就是错的;
所以需要递推去分组;
我也是看了别人的程序后才彻底明白的,具体看代码;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<climits>
#include<list>
#include<stack>
#include<cmath>
#define ll long long
#define MAX 310000
#define mem(a) memset(a,0,sizeof(a))
#define mems(a) memset(a,-1,sizeof(a))
using namespace std;
int arr[MAX];
ll dp[5500][5500];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
int i;
for(i=1;i<=n;++i)
{
scanf("%d",&arr[i]);
}
sort(arr+1,arr+n+1);
int j;
dp[0][0]=0;
int num_long,num_short;
num_long=n%k;//较长组的个数
num_short=k-num_long;//较短组的个数
int len=n/k;//短组的长度
for(i=0;i<=num_long;++i)
{
for(j=0;j<=num_short;++j)
{
if(i==0&&j==0)
{
continue;
}
int pos=i*(len+1)+j*len;//当前分了多少个,也是当前所分的组的最后一个元素在arr中的坐标
dp[i][j]=INT_MAX;
if(j>0)
{
dp[i][j]=min(dp[i][j],dp[i][j-1]+arr[pos]-arr[pos-len+1]);
}
if(i>0)
{
dp[i][j]=min(dp[i][j],dp[i-1][j]+arr[pos]-arr[pos-len]);
}
}
}
printf("%lld\n",dp[num_long][num_short]);
}