Minimization CodeForces - 571B(DP)

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/81698272

Minimization

题目链接:CodeForces - 571B

题意:给出长度为n的数组A,在将A重新排序后要求     \sum_{i=1}^{n-k}\left | A[i]-A[i+k] \right |    的值最小;

上式可以写成这样的:

|A[1]-A[1+k]|+|A[2]-A[2+k]|+|A[3]-A[3+k]|+......+|A[n-k+1]-A[n]|

=

|A[1]-A[1+k]|+|A[1+k]-A[1+k+k]|+|A[1+k+k]-A[1+k+k+k]|+......+

|A[2]-A[2+k]|+|A[2+k]-A[2+k+k]|+|A[2+k+k]-A[2+k+k+k]|+......+

|A[3]-A[3+k]|+|A[3+k]-A[3+k+k]|+|A[3+k+k]-A[3+k+k+k]|+......+

......

|A[k]-A[k+k]|+|A[k+k]-A[k+k+k]|+|A[k+k+k]-A[k+k+k+k]|

|A[1]-A[1+k]|+|A[2]-A[2+k]|+|A[3]-A[3+k]|+......+|A[n-k+1]-A[n]|= |A[1]-A[1+k]|+|A[1+k]-A[1+k+k]|+|A[1+k+k]-A[1+k+k+k]|+......+ |A[2]-A[2+k]|+|A[2+k]-A[2+k+k]|+|A[2+k+k]-A[2+k+k+k]|+......+ |A[3]-A[3+k]|+|A[3+k]-A[3+k+k]|+|A[3+k+k]-A[3+k+k+k]|+......+ ......+ |A[k]-A[k+k]|+|A[k+k]-A[k+k+k]|+|A[k+k+k]-A[k+k+k+k]|

由上式可知,可以将A分为k组,那么怎样结果最小呢?将A排序后,每一组中的数是相邻的这样结果最小;

最终排序为:A1, A2, A3, A4, ..., Ak, A1, A2, A3, A4, ..., Ak...;(A1就表示第一组数);

假设A为1, 2, 3, 4, 5, 6, 7, 8, 9;k=3;第一组就是1, 2, 3;第二组是4, 5, 6;第三组是7, 8, 9;

最后的排列方式为:1, 4, 7, 2, 5, 8, 3, 6, 9;结果最小;

长度为n的数组分为k组并不一定能够平均分开,一定是分为长度为n/k和(n/k)+1两种长度;长度为n/k+1的有n%k组,长度为n/k的有k-n%k组;

令dp[i][j]表示分为i组长的,j组短的后得到的最小结果, p=n/k+1, q=n/k;

dp[i][j]=min(dp[i][j], dp[i-1][j]+A[i*p+j*q]-A[i*p+j*q-p+1], dp[i][j-1]+A[i*p+j*q]-A[i*p+j*q-q+1]);

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
int n, k;
ll a[maxn], dp[5010][5010];
int main(){
	scanf("%d%d", &n, &k);
	for(int i=1; i<=n; i++){
		scanf("%lld", &a[i]);
	}
	sort(a+1, a+1+n);
	int lg=n%k, sg=k-lg;
	int ln=n/k+1, sn=n/k;
	dp[0][0]=0;
	for(int i=0; i<=lg; i++){
		for(int j=0; j<=sg; j++){
			if(i==0&&j==0) continue;
			dp[i][j]=INF;
			int pos=i*ln+j*sn;
			if(i) dp[i][j]=min(dp[i][j], dp[i-1][j]+a[pos]-a[pos-ln+1]);
			if(j) dp[i][j]=min(dp[i][j], dp[i][j-1]+a[pos]-a[pos-sn+1]);
		}
	}
	printf("%lld\n", dp[lg][sg]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81698272
今日推荐