luoguP4343自动刷题机(二分标准题)

https://www.luogu.org/problem/P4343
参考博客:https://www.luogu.org/blog/ofnoname/solution-p4343

这真是一语点醒梦中人啊! 其实我们只需要掌握好一种二分答案的正确写法就行了,不用非要是标准的(看不懂没关系, 说给自己听的)

以下为那位博主的分析,我觉得特别好

容易发现,对于给定的序列,n越大能过的题是越少的所以可以二分来求刚好过k道题左右边界

若mid大于k,即做得太多了,就将l右移。

若mid小于k,即做得太少了,就将r左移。

求左边界,需要在mid等于k时将r左移,求右边界时则需将l右移。这个很好理解。
(这就是我们在哪写ans = mid的依据了)

印象里二分写法极多,但现在普遍应用 l<=r, l=mid+1, r=mid-1这个版本了,虽然要多记录一个ans,但是却在单调增单调时都能工作,并且可以轻松应对无解的情况。

注意这种写法l应设为1,r设为无穷大即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int k, l;
long long a[100000+9];

long long check(long long n) {
	long long sum = 0, num = 0;
	for(int i = 1; i <= l; i++) {
		sum += a[i];
		sum = max(sum, (long long)0);
		if(sum >= n) {num++, sum = 0;}
	}
	return num;
}

int main() {
	scanf("%d%d",&l, &k);
	for(int i = 1; i <= l; i++) scanf("%lld", &a[i]);
	long long l = 1, r = 1e18, mid, mn = -1, mx = -1;// l 设为1, r为INF(真正的INF 
	while(l <= r) {
		mid = (l+r)>>1;
		if(check(mid) <= k) {
			r = mid - 1;
			if(check(mid) == k) mn = mid;//找最小值->需要在合法的时候把r左移,所以在更新r的地方写‘=’ 
		} else l = mid + 1;
	}
	l = 1, r = 1e18;
	while(l <= r) {
		mid = (l+r)>>1;
		if(check(mid) >= k) {
			l = mid + 1;
			if(check(mid) == k) mx = mid;//找最大值->需要在合法的时候把l右移, 所以... **让mx越来越大**
		}else r = mid - 1;
	}
	if(mn == -1) printf("-1");//判断不合法情况 
	else printf("%lld %lld", mn, mx);
}
原文地址:https://www.cnblogs.com/tyner/p/11289044.html