nitacm 2019校赛D雷顿女士与分队(hard version) dp
题目:https://ac.nowcoder.com/acm/contest/2995/D
题意:
n个人,恰好分成n/k队,每队至少有k个人
n个人有实力值a[i],每个队矛盾值为队内实力最大值减去最小值
求所有队矛盾值之和
思路:
显然先将所有人的能力值a[i]进行排序
设dp[i]为:从第1个人分配到第k个人,矛盾因数总和最小值
状态转移方程:
当i%k==0时,每队恰好k个人,恰好n/k队
当i%k!=0时,必有队伍大于k个人,dp[i]的矛盾因数总和最小值有两个来源:
一个是dp[i-1],意味着a[i]和a[i-1]一队,
一个是dp[i-k],意味着a[i]和a[i-k+1],k个人一队。
dp[0]设为0,第0个人矛盾因数总和最小值为0,其余设为inf,dp从第k个人开始计算
附上代码:
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f const int maxn=2e5+10; int a[maxn],dp[maxn]; int main() { int T; scanf("%d",&T); while(T--) { int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%d",&a[i]); sort(a+1,a+n+1); for(int i=1;i<=n;i++)dp[i]=inf; dp[0]=0; for(int i=k;i<=n;i++) { if(i%k==0)dp[i]=dp[i-k]+a[i]-a[i-k+1]; else { dp[i]=min(dp[i-k]+a[i]-a[i-k+1],dp[i-1]+a[i]-a[i-1]); } } cout<<dp[n]<<endl; } return 0; }
附上另一个小可爱的代码: