题目链接:https://codeforces.com/contest/1133/problem/E
题目大意:有n个人每个人对应一个值ai,要求组成至少一个,至多k个队伍,且队伍内的人权值差最大不超过5,问此时在队伍中的最多队员数
先对数组从小到大排个序
假设表示当前将第i个人作为新的队伍的第一个人,且此时有j个非空队伍的状态对应的最大在队伍里的队员数量
转移方向:
1.跳过第i个,直接转移到
2,第i个单独形成一个新的队列 这个地方需要贪心地想一下,一旦形成了一个新的队列,题目的要求又没有规定必须要k个非空,所以一旦形成一个新的队伍,就尽可能多得往这个队里插入队员是最好的
记录表示一旦选第i个选手作为这个队中能力最低的,这个队最多可以由多少人
可以转移到
最后的答案就是max ( dp[i][j] )
比较骚的写法是 dp[n][m] (下标从0开始)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5005;
const int inf=99999999;
int a[maxn];
int dp[maxn][maxn];
int cnt[maxn];
int main()
{
//dp[i][j]表示第i个人在第一个的时候,此时有j个非空队,队伍中的最大人数
memset(dp,0,sizeof(dp));
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
for(int i=0;i<n;i++)
{
cnt[i]=upper_bound(a,a+n,a[i]+5)-a-i;//如果i号人站第一个,这个队最多有多少人
}
//for(int i=0;i<n;i++)cout<<cnt[i]<<' ';
//cout<<endl;
int ans=0;
for(int i=0;i<n;i++)//第i号人
{
for(int j=0;j<=m;j++)//当前队数
{
dp[i+1][j]=max(dp[i][j],dp[i+1][j]);//是否跳过第i+1个人
ans=max(ans,dp[i+1][j]);
if(j+1<=m)
{
dp[i+cnt[i]][j+1]=max(dp[i+cnt[i]][j+1],dp[i][j]+cnt[i]);
ans=max(dp[i+cnt[i]][j+1],ans);
}
}
}cout<<ans<<endl;
return 0;
}