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;	
}

posted @ 2022-07-14 21:49  FxorG  阅读(19)  评论(0编辑  收藏  举报