P2719 分队问题 - oiClass

题意简化

求一种分配方案:

  1. 最大化队伍总数;
  2. 在满足 1 的情况下最小化最多人的队伍人数。

题目思路

由于本题目的数据量高达 106,且贪心算法也许不成立,所以需要考虑 nlogn 的算法!

具体的,对于一个人的需求 ai,如果小于 ai 的数先被选走,那么 ai 可能问题:

不存在人数为 ai 的团队(答案并非最优)

证明:

3
1
2
3
1 3

那么,由于上述原因,要使得存在 nlogn 算法就务必需要满足无后效性。

故以使用动态规划与二分答案解答。

我们首先应该对 ai 排序,以消除后效性!

由于 1 是必要条件,所以通过动态规划队伍总量的最大值,然后使用二分找到最小的队伍人数;

那么动态转移方程成了必不可缺的内容!

动态转移方程:

对于每个 ai 有两种可能:

  1. 被选;
  2. 选择。

如果是被选

则代表 ai 处于队伍中间,则 ai 团队的起始人任然不变,即 last[i]=last[i1]

如果是选择

则代表自己是对于开头,即 last[i]=i,并更新 DP 数组的答案。

此题方程定义参考沈子扬同学的定义。

当然,这样定义不便于代码的撰写,于是我们将操作 2 提前一位,即在原选择的情况下自己是团队的最后一位!

思路结。

HACK 补充:

10
3 3 3 3 3 4 4 4 4 4
2 5
6
1 1 3 3 3 3
3 4

From Discuss!

AC Code:

#include<bits/stdc++.h>
using namespace std;
int n,a[1000010],dp[1000010],last[1000010];
int work(int mid)
{
	memset(dp,-1,sizeof(dp));
	memset(last,0,sizeof(last));
	dp[0]=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]<=i && dp[last[i-a[i]]]>=0 && last[i-a[i]]+mid>=i)dp[i]=dp[last[i-a[i]]]+1;
		if(dp[i]>=dp[last[i-1]])last[i]=i;
		else last[i]=last[i-1];
	}
	return dp[n];
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	int l=0,r=n+1,num=work(n);
	while(r-l>1)
	{
		int mid=l+(r-l)/2;
		if(work(mid)==num)r=mid;
		else l=mid;
	}
	printf("%d %d",num,r);
	return 0;
}
posted @   Cheerimy  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示