相当于是把%k相同的位置的数分为一组,组与组之间互不干扰
然后发现一组中可以任意打乱顺序,并且一定是单调排列最好,那个值就是最大值减最小值
所以我给所有数排序以后,同一组应该选连续的一段最好
然后发现有$n\%k$组元素个数是$frac{n}{k}+1$,剩下的$k-n\%k$组元素个数是$frac{n}{k}$
所以设dp[i][j]表示第一类已经选完了i组,第二类选完了j组,目前为止的最小代价
通过这个i和j可以推出现在已经选到了哪个元素
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=3e5+10,maxk=5005; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int f[maxk][maxk],N,K,A[maxn]; 16 17 int main(){ 18 int i,j,k; 19 N=rd(),K=rd(); 20 for(i=1;i<=N;i++) A[i]=rd(); 21 sort(A+1,A+N+1); 22 int a=N%K,b=K-a,n1=N/K+1,n2=N/K; 23 CLR(f,127); 24 for(i=0;i<=a;i++){ 25 for(j=0;j<=b;j++){ 26 if(!i&&!j) f[i][j]=0; 27 else{ 28 if(i) f[i][j]=min(f[i][j],f[i-1][j]+A[i*n1+j*n2]-A[(i-1)*n1+j*n2+1]); 29 if(j) f[i][j]=min(f[i][j],f[i][j-1]+A[i*n1+j*n2]-A[i*n1+(j-1)*n2+1]); 30 } 31 } 32 } 33 printf("%d ",f[a][b]); 34 return 0; 35 }