CF571B Minimization
https://www.luogu.com.cn/problem/CF571B
还是有点厉害的 *2000。
考虑从 1 想起,那是不是 \(1+k,1+2k,1+3k...\),那么发现可以按 \(\mod k\) 分组,然后你会发现这些组的长度仅有 \(\lfloor\dfrac{n}{k}\rfloor\),\(\lfloor\dfrac{n}{k}\rfloor+1\),又考虑一定是选择排序后连续的一段,因为这样子就是 \(\max-\min\),其他情况都不更优(这也是典),那么 dp 即可。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N=(int)(3e5+5);
int n,k,a[N],cnt[N],f[5005][5005];
signed main() {
cin.tie(0); ios::sync_with_stdio(false);
// cout<<"qwq";
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) {
++cnt[(i-1)%k];
}
int res1=0,res2=0,len1=n/k,len2=n/k+1;
for(int i=0;i<k;i++) {
if(cnt[i]==len1) ++res1;
else if(cnt[i]==len2) ++res2;
// cout<<cnt[i]<<'\n';
}
// cout<<res1<<" "<<res2<<'\n';
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=0;i<=res1;i++) {
for(int j=0;j<=res2;j++) {
if(!i&&!j) continue ;
int p=i*len1+j*len2;
if(i>=1&&p>=len1) f[i][j]=min(f[i][j],f[i-1][j]+a[p]-a[p-len1+1]);
if(j>=1&&p>=len2) f[i][j]=min(f[i][j],f[i][j-1]+a[p]-a[p-len2+1]);
}
}
cout<<f[res1][res2];
return 0;
}