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

 

附上另一个小可爱的代码:

https://www.cnblogs.com/mcq1999/p/12006696.html

posted @ 2019-12-15 21:26  myrtle  阅读(284)  评论(0编辑  收藏  举报