Codeforces 571B Minimization

时间:2024-01-18 21:41:02

http://codeforces.com/problemset/problem/571/B

给出一个序列,可以任意调整序列的顺序,使得给出的式子的值最小

Codeforces 571B Minimization

思路:我们可以把序列分解,变成k条链,n%k条n/k+1长度的,k-n%k条n/k长度的,然后发现,如果要求这个和最小,那么这些链我们都可以变成递增,而且链里面相邻元素是排序后的相邻元素才是最优的。这么样,我们考虑把数组排序,然后dp

考虑这样dp:f[i][j]代表n/k+1长度的有i条,n/k长度有j条,代表能删掉的最大的数,由于i和j确定以后,序列的长度我们也知道了,这样就能够转移了,最后答案就是a[n]-a[1]-f[num1][num2]

 #include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
int a[],f[][];
int n,K;
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
int main(){
n=read();K=read();
for (int i=;i<=n;i++) a[i]=read();
std::sort(a+,a++n);
int num1=n%K,len1=n/K+;
int num2=K-n%K,len2=n/K;
a[]=a[];
for (int i=;i<=num1;i++)
for (int j=;j<=num2;j++){
if (i){
int k=(i-)*len1+j*len2;
f[i][j]=std::max(f[i][j],f[i-][j]+a[k+]-a[k]);
}
if (j){
int k=i*len1+(j-)*len2;
f[i][j]=std::max(f[i][j],f[i][j-]+a[k+]-a[k]);
}
}
printf("%d\n",a[n]-a[]-f[num1][num2]);
return ;
}