Codeforces 1133E - K Balanced Teams - [DP]

题目链接:https://codeforces.com/contest/1133/problem/C

 

题意:

给出 n 个数,选取其中若干个数分别组成 k 组,要求每组内最大值与最小值的差值不超过5,求 k 组合起来最多可以放多少个数。

 

题解:

a[1n] 从小到大排序,排序后每个组必定可以视为数组 a 上一段连续区间,

f[i][j] 表示到第 i 个数为止,前面组成 j 组,最多可以包含多少个数。

那么,考虑第 i 个数选取与否,如果不选,那么 f[i][j]=f[i1][j]

如果选,那么必然是第 i 个数所在组人数加上前面那些组人数,假设 p 表示距离 a[i] 左侧最远的那个位置(满足 a[i]a[p]5),f[i][j]=(ip+1)+f[p1][j1]

 

AC代码:

用lower_bound找 p,时间复杂度 O(nlogn+nk)

复制代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
int n,k,ans;
int a[maxn];
int f[maxn][maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);

    ans=f[1][1]=1;
    for(int i=2;i<=n;i++)
    {
        int p=lower_bound(a+1,a+i+1,a[i]-5)-a;
        for(int j=1;j<=min(k,i);j++)
        {
            f[i][j]=max(f[i-1][j],(i-p+1)+f[p-1][j-1]);
            ans=max(ans,f[i][j]);
        }
    }
    cout<<ans<<endl;
}
复制代码

 

线性维护 p,时间复杂度 O(nk)

复制代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
int n,k,ans;
int a[maxn];
int f[maxn][maxn];
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);

    ans=f[1][1]=1;
    int p=1;
    for(int i=2;i<=n;i++)
    {
        while(p<i && a[i]-a[p]>5) p++;
        for(int j=1;j<=min(k,i);j++)
        {
            f[i][j]=max(f[i-1][j],(i-p+1)+f[p-1][j-1]);
            ans=max(ans,f[i][j]);
        }
    }
    cout<<ans<<endl;
}
复制代码

 

posted @   Dilthey  阅读(452)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
历史上的今天:
2018-05-03 CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]
点击右上角即可分享
微信分享提示