http://codeforces.com/problemset/problem/571/B
给出一个序列,可以任意调整序列的顺序,使得给出的式子的值最小
思路:我们可以把序列分解,变成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]
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 int a[500005],f[5005][5005]; 7 int n,K; 8 int read(){ 9 int t=0,f=1;char ch=getchar(); 10 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 11 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 12 return t*f; 13 } 14 int main(){ 15 n=read();K=read(); 16 for (int i=1;i<=n;i++) a[i]=read(); 17 std::sort(a+1,a+1+n); 18 int num1=n%K,len1=n/K+1; 19 int num2=K-n%K,len2=n/K; 20 a[0]=a[1]; 21 for (int i=0;i<=num1;i++) 22 for (int j=0;j<=num2;j++){ 23 if (i){ 24 int k=(i-1)*len1+j*len2; 25 f[i][j]=std::max(f[i][j],f[i-1][j]+a[k+1]-a[k]); 26 } 27 if (j){ 28 int k=i*len1+(j-1)*len2; 29 f[i][j]=std::max(f[i][j],f[i][j-1]+a[k+1]-a[k]); 30 } 31 } 32 printf("%d ",a[n]-a[1]-f[num1][num2]); 33 return 0; 34 }