C. LuoTianyi and the Show(贪心)

题目

题意

给定n个(空降人员),m个坑位(下标为1到m)。

对于每个n个空降人员,对应有数值x,-2<=x<=m

  • 如果x为-1,表示需要把当前空降人员,落地到已经被占用的坑位中最左侧人员左边。如果下标1已经被占用,说明当前空降人员无位置了,则丢弃该空降人员。如果此时m个坑位无人占用,则落地到下标m。
  • 如果x为-2,表示需要把当前空降人员,落地到已经被占用的坑位中最右侧人员右边。如果下标m已经被占用,说明当前空降人员无位置了,则丢弃该空降人员。如果此时m个坑位无人占用,则落地到下标1。
  • 如果x为正数,则落地到位置x,如果该位置已经被占用,说明当前空降人员无位置了,则丢弃该空降人员。

现在,给定这n个空降人员的x,你可以安排这n个空降人员的落地顺序。问,最多能保证多少人顺利落地到这m个坑位中。

思路

对于x>0的情况,如果存在重复下标,必定只有一个能落地坑位,其他相同下标只能原地去世。我们将x>0的元素排序去重后,得到的总数(不妨设为h),即为最小保证数量。

再考虑只用-1(不妨表示-1的数量为first),不用-2的情况,那么此时,我们可以贪心地,从右往左填充,此时最多填充数量为 min(first + h, m)

类似的,考虑只用-2(不妨表示-2的数量为second),不用-1的情况,那么此时,我们可以贪心地,从左往右填充,此时最多填充数量为 min(second + h, m)

如果想要同时利用-1和-2呢?根据它们的规律,我们需要设置一个标准杆(不妨用第i个)。我们先落地该人员。之后,对于-1 的人员,我们只需要贪心把他们落地在x[i]之前的下标;对于-2的人员,我们可以贪心把他们落地在x[i]之后的下标。
我们枚举做为标准杆的位置,并预处理,计算每个标准杆,前面和后边的空闲坑数量left[i],right[i],从而计算出该场景下能填充的最多人数。

描述的比较抽象(摆烂),结合代码理解。

代码

#include<string>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn = 200010;

int n, m;
int x[maxn], v;
int Left[maxn], Right[maxn];

void solve() {
	scanf("%d%d", &n, &m);
	int h = 0;
	int first = 0, second = 0;
	for (int i = 0; i < n; ++i) {
		scanf("%d", &v);
		if (v == -1) {
			++first;
		} else if (v == -2) {
			++second;
		} else {
			x[++h] = v;
		}
	}
	sort(x + 1, x + h + 1);
	h = unique(x + 1, x + h + 1) - x - 1;
	// cal left
	Left[1] = x[1] - 1;
	for (int i = 2; i <= h; ++i) {
		Left[i] = Left[i-1] + x[i] - x[i-1];
	}
	
	// cal right
	Right[h] = m - x[h];
	for (int i = h - 1; i >= 1; --i) {
		Right[i] = Right[i+1] + x[i+1] - x[i];
	}
	
	// cal ans
	int ans = min(m, h + max(first, second)), tmp;
	for (int i = 1; i <= h; ++i) {
		tmp =  min(x[i] - 1, i - 1 + min(Left[i], first)) + 
			   min(m - x[i], h - i + min(Right[i], second)) + 1;
		ans = max(ans, tmp);
	}
	printf("%d\n", ans);
} 
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		solve();
	}
}
/*

*/

同名GZH: 对方正在debug

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值