【DP】【分队问题】

题目描述

给定n 个选手,将他们分成若干只队伍。其中第i 个选手要求自己所属的队伍的人数大等于a[i]人。

在满足所有选手的要求的前提下,最大化队伍的总数。
注:每个选手属于且仅属于一支队伍。
输入格式
第一行一个整数n,表示人数。
以下n 行,每行一个整数表示a[i]。
输出格式
输出队伍总数的最大值。数据保证有解。


样例输入
5
2
1
2
2
3


样例输出
2


数据范围
对于20%的数据,n <= 10
对于40%的数据,n <= 1000
对于60%的数据,n <= 10000
对于100%的数据,1 <= n <= 10^6


Solution:

最开始想到贪心。


先把A[ i ] 排序。

然后我们从大到小依次加入队伍就好了。

3 2 2 2 1

先把 3 2 2 加入

再把 2 1 加入 就可以了。

但是实际上这东西是错的。

例子

3 3 3 3 2 2 1

变成             3 3 3。3 2 1。

实际上可以  1 。2 2。3 3 3 3

所以贪心有问题。


考虑DP

F[i] 表示前 i 个人可以最多分成的队伍数目。

显然 如果第 i 个人对队伍数目做出贡献,当且仅当 满足了 第i个人的要求 A[i] 

所以 F [ i ] =Max{F[ k ] } +1  其中 0 < K < = i - A[ i ]

所以 可以维护 一个 最大值 G [ k ] 表示 F[ 1..k ] 的 最大值。

每次修改 了 F [ i ] 的话 就是 G [ i ] =Max { F [ i ], G [ i -1 ] }

这就避免了每次查找 max F [ k ] 都要从 头 到 i- A [ i ] 扫描一遍。 

所以时间复杂度 为 O(N)


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+5,inf=x3f3f3f3f;
inline void _read(int &x){
    char t=getchar();bool sign=true;
    while(t<'0'||t>'9')
    {if(t=='-')sign=false;t=getchar();}
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
    if(!sign)x=-x;
}
int n,f[maxn],s[maxn],g[maxn];
int main(){
	_read(n);
	int i,j,cur;
	for(i=1;i<=n;i++)_read(s[i]);
	sort(s+1,s+1+n);
	for(i=1;i<=n;i++){
		if(i<s[i]){g[i]=g[i-1];continue;}
		cur=i-s[i];
		if(cur>i-1)cur=i-1;
		f[i]=g[cur]+1;
		g[i]=max(g[i-1],f[i]);
	}
	cout<<f[n];
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值