Codeforces Round #598 (Div. 3)- E. Yet Another Division Into Teams - 動態規劃

【Problem Description】
給你\(n\)個數,將其劃分為多組,對于每個組定義其\(d\)值為 組內的最大值減最小值,問如何劃分使得最終所有組的\(d\)值之和最小,每個組至少要保證有\(3\)個數,
【Solution】
將所有值從小到大排序,然后我們知道最多有\(5\)個人劃分到同一組中,如果有\(6\)個人,那么劃分為兩組一定比劃分為一組更優,
定義\(dp[i]\)表示前\(i-1\)個人劃分后的最小\(d\)值和為\(dp[i]\),假設前\(i-1\)個人已經劃分好了,然后就是確定哪些人與第\(i\)個人分為一組,題目要求至少\(3\)個人,而我們又知道最多\(5\)個人,所以列舉第\(j\in[i+2,i+4]\)個人,選擇\(a[j]-a[i]\)最小的那個\(j\),將\([i,j]\)這些人分為一組即可,
【Code】
/*
* @Author: _Simon_
* @Date: 2019-11-06 10:55:21
* @Last Modified by: Simon
* @Last Modified time: 2019-11-06 10:55:21
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 200005
#define INF 0x3f3f3f3f
pair<int,int>a[maxn];
int dp[maxn],p[maxn]; //dp[i]表示前i-1個人劃分好后的最小d值和
int ans[maxn]/*每個人分在第幾組*/,root,cnt/*總共有多少個組*/;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].first,a[i].second=i;
sort(a+1,a+n+1); //從小到大排序
memset(dp,INF,sizeof(dp));dp[1]=0;
for(int i=1;i<=n;i++){
for(int j=2;j<=4&&i+j<=n;j++){
int diff=a[i+j].first-a[i].first;
if(dp[i+j+1]>dp[i]+diff){
dp[i+j+1]=dp[i]+diff;
p[i+j+1]=i; //記錄方案,表示[i,i+j]這些人分為一組
}
}
}
root=n+1;cnt=1;
while(root!=1){
for(int i=root-1;i>=p[root];i--){ //[p[root], root-1]這些人為同一組
ans[a[i].second]=cnt;
}
cnt++;root=p[root]; //列舉下一組
}
cout<<dp[n+1]<<' '<<cnt-1<<endl;
for(int i=1;i<=n;i++) cout<<ans[i]<<' ';cout<<endl;
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/131562.html
標籤:其他
