二分题目练习

wscg,重新学习二分答案。。

P1843 奶牛晒衣服

\(mid\)是我们花费的时间,对于每件衣服判断再\(mid\)时间内能不能被自然烘干,如果不能就需要烘干机,计算需要烘干机的时间(烘干机是独立的),如果时间在\(mid\)以内说明是\(mid\)是合法的,否则\(mid\)就不合法。

int q[N];
bool chek(int mid) {
	int s = 0;
	for (int i = 1; i <= n; i++) {
		if (q[i] - mid * a > 0) {
			s += ceil((q[i] - mid * a) / b);
		}
	}
	if (s <= mid) return 1;
	else return 0;
}
void solve() {
	cin >> n >> a >> b;
	for (int i = 1; i <= n; i++) {
		cin >> q[i];
	}
	int l = 0, r = 1e9;
	while (l <= r) { 
 //因为是要找最小值,所以mid合法时更新的是r,不合法时更新l。
		int mid = (l + r) / 2;
		if (chek(mid))
			r = mid - 1;

		else
			l = mid + 1;
	}
	cout << l << '\n';
}

P1577 切绳子

比较简单的浮点数二分,不用担心边界问题。

double a[N];
bool check(double mid) {
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		if (a[i] >= mid) {
			cnt += a[i] / mid;
		}
	}
	if (cnt < m)
		return 0;
	else
		return 1;
}
void solve() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	double l = 0.0, r = 100000000.0;
	while (r - l > eps) {
		double mid = (l + r) / 2.0;
		if (check(mid)) {
			l = mid;
		} else {
			r = mid;
		}
//		printf("%.8lf %.8lf\n", l, r);
	}
	printf("%.1lf\n", l);
}

P1182 数列分段 Section II

数列分段,关键点在于判断分的段数是否合法,如果最少需要段数比我们需要的段数要小,那我们可以通过在每一段的内部分段使得段数达到\(K\)但是如果要多的话显然是不合法的。

其次,由于二分时的区间取值问题,很明显,对于\(L\)的赋值应该取数列中的最大值,而r应该取数列的总和。(如果$L4赋值为0或1,第4个点会wa)。

bool chek(int mid) {
	int sum = 0, k = 0;
	for (int i = 1; i <= n; i++) {
		if (sum + a[i] <= mid)
			sum += a[i];
		else {
			sum = a[i];
			k++;
		}
	}
	if (k >= m) return 0;
	else return 1;
}

void solve() {
	cin >> n >> m;
	int l = 0, r = 1e9;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		l = max(l, a[i]);
	}
	while (l <= r) {
		int mid = (l + r) / 2;
		if (chek(mid))
			r = mid - 1;
		else
			l = mid + 1;
	}
	cout << l << '\n';
}

/*
4 2 4 5 1
*/

P3743 小鸟的设备

这个题比较的毒,\(check\)函数十分好想,但是\(r\)数据范围必须开到1e10,但是由于我们处理数据肯定是希望精度越高越好,但是如果\(eps\)开到了1e-8,那么代码就会\(TLE\),这就是为什么一直过不了第19个点的原因,因此\(eps\)只要设为1e-5就可以了。

double b[N], a[N];
double p;
bool chek(double mid) {
	double sum = 0;
	for (int i = 1; i <= n; i++) {
		double k = b[i] / a[i];
		if (k < mid) {
			sum += (mid * a[i] - b[i]) / p;
		}
	}
	if (sum > mid) return 0;
	else return 1;
}
void solve() {
	cin >> n >> p;
	double s = 0;
	for (int i = 1; i <= n; i++) {
		cin >> a[i] >> b[i];
		s += a[i];
	}
	if (p >= s) {
		cout << "-1.000000000" << '\n';
		return;
	}
	double l = 0.0, r = 1e10;
	while (r - l > eps) {
		double mid = (l + r) / 2.0;
		if (chek(mid))
			l = mid;
		else
			r = mid;
	}
	printf("%.8lf\n", l);
}
/*
*/

P3853 [TJOI2007] 路标设置

这和之前选石头的题目思路基本一致,主要注意一下边界问题即可。

bool chek(int mid) {
	int y = k;
	int la = 0;
	for (int i = 1; i <= n; i++) {
		if (y < 0) break;
		if (a[i] - la <= mid) {
			la = a[i];
		} else {
			la = la + mid;
			i--;
			y--;
		}
	}
	if (y >= 0)
		return 1;
	else
		return 0;
}
void solve() {
	cin >> L >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	int l = 0, r = L;
	while (l <= r) {
		int mid = (l + r) / 2;
		if (chek(mid)) {
			r = mid - 1;
		} else
			l = mid + 1;
	}
	cout << l << '\n';
}
posted @ 2024-07-05 17:47  ZhangDT  阅读(34)  评论(0)    收藏  举报