二分答案——洛谷P2440木材加工

  1. 题目描述
    二分答案——洛谷P2440木材加工_第1张图片
  2. 问题分析
    这个题目是一类典型的二分答案问题,题目中给出我们需要将给定的长度切割成相应的K段,并且保证切割的小段的最大长度,那么我们怎么做呢,必然是在一定的区间枚举出来该切成多少才能满足切成k段并且保证长度最大,其实这里我们可以考虑二分的思想,比方说,我们最大能切的长度必然不会比原来的木头的最大的那一根还要长,并且我们确定最小可以切出1cm,若是1cm切不出便输出0.
    那么二分区间的左端点l = 1, 右端点r = max({l1, l2, l3, l4…ln)
    我们该怎么找呢在这个二分区间内我们就像二分查找类似的写法,在左边子区间或者右边子区间逐步逼近找出误差最小的答案,我们这时不能像二分查找对应元素那样去考虑,而是写一个check函数,我比较喜欢叫check,然后我们将每一个木头切割这个长度(向下取整)然后将可以切割的数量相加在与给定切割的数目k作为比较,如果res >= k那么证明,所切割的值偏小,那么我们应该往右区间去找,反之找左区间。
bool check(LL x) {
	LL res = 0;
	for (int i = 1; i <= n; i++) {
		res += a[i] / x;
	}
	return res >= K;
}
  1. AC代码:
#include 
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 5;

LL a[maxn];

int n;
LL K;
LL l = 1, r = -1;

bool check(LL x) {
	LL res = 0;
	for (int i = 1; i <= n; i++) {
		res += a[i] / x;
	}
	return res >= K;
}

int main() {
	scanf("%d%lld", &n, &K);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
		r = max(r, a[i]);
	}
	LL ans = 0;
	while (l <= r) {
		LL mid = (l + r) >> 1;
		if (check(mid)) {
			ans = mid;
			l = mid + 1;
		} else {
			r = mid - 1;
		}
	}
	printf("%lld\n", ans);
	return 0;
} 

总结:
二分答案是在竞赛中常考的类型,其思想也是基于二分的变形,分析问题,给出以下常见题目中的关键字,判断是否使用二分。
第一类问题:
二分答案应用求解问题
求最大长度中的可能最小值是多少
问最小重量的最大值是多少

第二类问题:
最少要多少才能满足要求
在满足限制的情况下最大值是多少

对于第二类问题,我们可以抽象
对于x, 有一个函数f(x), 值域为{0,1}
求满足f(x) = 0时 x的最大值

将第一类问题转换为第二类问题

对于第一类问题
我们抽象:

对于x, 有一个函数f(x)
求当满足f(x) <= M时x的最大值 。

你可能感兴趣的:(落谷,二分)