C. Doremy‘s IQ(贪心)

Problem

给出一个长度为n的序列a,按次序遍历。现在给出一个q,按次序对 a [ i ] a[i] a[i]进行测试。测试时,执行以下操作:

  • 如果 q ≥ a [ i ] q \geq a[i] qa[i], q不变
  • 如果 q < a [ i ] q < a[i] q<a[i] q = q − 1 q = q - 1 q=q1

可以跳过某个测试,q不发生变化。当q = 0时,终止。
问最多可以执行几次测试,输入最优方案的01序列。

Solution

首先考虑到前面执行测试会影响到后面的情况,所以就可以考虑反向思考。当然也可以正向思考,只不过正向思考比较麻烦。
方法一:正向思考,贪心+二分
方法二:逆向思考,贪心

One

结论:
![在这里插入图片描述](https://img-blog.csdnimg.cn/3940d705ac6b4bcaa35a4febbb9e8f87.png)

那些会使q减小的操作应尽量靠后。
对于方案中的第一个使q减小的测试,其实可以将其调换到最后面的没有进行进行测试的一个位置。
不断执行上面的调换,直到该位置后面所有的都进行了测试。
该调换不会使得结果变小,只会使得结果更优。
最终会形成一个后缀。在后缀中,无论 a [ i ] a[i] a[i] 的大小,都进行测试。
前面的部分,只有不会使q减小的进行测试。
最优方案应该使后缀尽量长。所以可以二分求解。

Two

逆向思考:假如q初始为0
为了让 会使q变小的测试尽量排在后面,
逆序遍历,如果 a [ i ] > q a[i] > q a[i]>q, q++。直到q 等于输入中q的值。
这之后,前面的只有 a [ i ] ≤ q a[i] \leq q a[i]q 才进行测试。

Code

这是方法一的代码(方法二代码很简单,就不写了)

bool check(int mid)
{
	int qq = q;
	for (int i = mid; i <= n; i++)
		if (a[i] > qq) qq--;

	return qq >= 0;
}

int main()
{
	IOS;
	int T; cin >> T;
	while (T--)
	{
		cin >> n >> q;
		for (int i = 1; i <= n; i++) cin >> a[i];
		
		int l = 1, r = n;
		while (l < r)
		{
			int mid = l + r >> 1;
			if (check(mid)) r = mid;//mid应该尽量小
			else l = mid + 1;//mid太小了,导致check中qq < 0
		}
		for (int i = 1; i <= n; i++)
			if (i < l) cout << (a[i] <= q ? 1 : 0);
			else cout << 1;
		cout << "\n";
	}


	return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

to cling

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值