Codeforces 571B Minimization

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\n",a[n]-a[1]-f[num1][num2]);
33     return 0;
34 }

 

posted @ 2016-06-28 18:24  GFY  阅读(305)  评论(0编辑  收藏  举报