专题六:二分查找(binary search)

挑战程序设计竞赛

1.Cable master POJ - 1064

这道题好容易错啊。

cf

1.Frog Jumps CodeForces - 1324C

(1)差点以为是动态规划。其实是一道简单的二分查找,不过还是有点容易错的,把这个题记下来。
(2)其实根本不用管有几个L,只要看在d的范围内有没有R就行。

#include<iostream>
#include<cstring>
using namespace std;
char str[200005];
const int INF = 1e9;
int fd(int id) {
	int len = strlen(str);
	for (int i = id; i < len; i++) {
		if (str[i] == 'R') return i;
	}
	return INF;
}
bool ok(int x){
	int len = strlen(str);
	int i = -1;
	while (len - i > x) {
		int id = fd(i + 1);
		if (id - i > x) return false;
		i = id;
	}
	return true;
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%s", str);
		int lb = 0, ub = 1e6;
		while (ub - lb > 1) {
			int mid = (lb + ub) / 2;
			if (ok(mid)) {
				ub = mid;
			}
			else {
				lb = mid;
			}
		}
		printf("%d\n", ub);
	}
	return 0;
}

2.B. Alyona and a Narrow Fridge

用二分搜索解此题确实很好。很容易证明其正确性,而且时间复杂度可以过的去。

第一次还把 int 撑爆了。在那个判断函数里面,ans一旦大于H就返回false,不要等到最后加完了再判断。真的是好容易错啊!

3.B. Ternary String

题解怪怪的,但是复杂度是线性,确实可以。求连续字串出现所有字母的最小长度。题解是用vector保存下来连续相等的串,这种解法还是很值得学习的。连续串一直都是代码有点难设计的问题。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
char a[200005];
 
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%s", a);
		int len = strlen(a);
		vector<pair<char, int> > v;
		for (int i = 0; i < len; i++) {
			if (v.empty() || a[i] != v.back().first) {
				v.push_back(make_pair(a[i], 1));
			}
			else v.back().second++;
		}
		int ans = 1e9;
		int sz = v.size();
		for (int i = 1; i < sz - 1; i++) {
			if (v[i - 1].first != v[i + 1].first) {
				ans = min(ans, v[i].second + 2);
			}
		}
		if (ans == 1e9) printf("0\n");
		else printf("%d\n", ans);
	}
	return 0;
}

4.C. Three Parts of the Array

二分搜索的题并不好写呀。实际上如果用双指针的话,还挺简单。

用双指针必须注意一个问题。就是p1, p2指的是还没加到sum1 或是 sum3中的元素还是已经加到sum1或是sum3中的元素。如果指的是还没加进去的元素,那么会产生问题。因为循环条件不管是 while(p2 > p1) 还是 while(p2 >= p1),都可能会出现漏加中间那个元素的情况。原因很简单,还没加上a[p1]或是a[p2],就跳出了循环。

尺取法一定要注意这个问题!

5.B. Chloe and the sequence

二分法太灵活了。这道题可以不断二分下去,然后看看这是数是前半段,还是后半段,或者是中间加进去的一个数。关键就是看是第几次加进去的数。

尤其要注意,要是算2的n次幂,要1LL << n,不要少LL,不然会把 int 撑爆。也不要误写成 2LL <<  n,这也是不对的。

因为C语言默认的整型常量都是 int 型的。

6.B. Two Cakes

这道题有点坑。因为有一句话“每个蛋糕都必须放在盘子里”。因此,二分法最容易错的地方就是那个函数的返回。一定要保证只要是满足的情况的一定要返回true,不满足的一定要返回false。且不满足的话,所有大于mid的值都不满足。这两点非常关键。

7.B. K-th Beautiful String

这个二分搜索的题不好写。过程有点复杂。其实就是找第 K 个全排列是什么。

我的思路是,我发现其实第一个b在倒数第2个位置时,有1种;在倒数第三个位置时,有2种,以此类推。二分搜出第一个b在第几个位置,然后算出第二个b的位置。这个方法看上去很简单,但是实现起来其实有点难度。但是熟练的话应该也不麻烦。

答案的思路和我差不多,但是他是每次把K减去1,2,3...... 这样子实现起来思路更清晰。

8.C. Maximum Median

在一个序列中,把任意一个元素加1,重复K次,问最大中位数。典型二分搜索。寻找到一个下标idx,使得下标为 N / 2 到 idx 都可以加到a[idx],且这种操作的次数不超过K。但是,这道题看上去简单,其实设计起来并不是那么顺利。

整数二分易错:一定要考虑,当N为1或者2时,二分循环进不去的,此时要额外考虑是否满足情况。

9.F Free Weights

这道题是2020.07.14的校队比赛题。用二分法轻松写出来。但是比赛完才想到用二分算法来写。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值