洛谷P4343 [SHOI2015]自动刷题机

题目

易得该题目中的(n)(k)具有单调性,满足二分的性质,因此该题目而已用二分来枚举(n),然后对于每个(n)模拟出它所对应的(k),然后注意注意代码细节,并且当当前(k)等于题目要求的(k)时,要分别向左和右二分,才能找出所有情况。

#include <bits/stdc++.h>
#define N 3000011   
#define int long long
using namespace std;
int n, k, x[N], sum[N], maxn, minn = 2147483647124544;
int check(int mid)
{
 	int l = 1, now = 0, tot = 0;
 	while (l <= n)//这里是不能二分的,因为不满足二分单调性。 
 	{
 		while (now < mid && l <= n)
 		{
 			now += x[l++];
 			now = max(now, 0LL);
 		}	
	 	if (now >= mid)	
 		tot++, now = 0;//此处l不能++, 因为循环里已经++了 
 	}
 	return tot;
}	
signed main()
{	
 	scanf("%lld%lld", &n, &k);  
 	for (int i = 1; i <= n; i++)
 	{
 		scanf("%lld", &x[i]); 
 	 	sum[i] = sum[i - 1] + x[i];
	 	if (sum[i] < 0) sum[i] = 0;
 	}
// 	printf("%lld ", check(3));
 	int l = 1LL, r = 1000000000000LL;//二分n
 	while (l <= r)
 	{
 		int mid = (l + r) >> 1;
 		if (check(mid) > k)//如果最终的结果比k大,n越大,k越小 
 			l = mid + 1;
	 	if (check(mid) < k)
	 		r = mid - 1;
	 	if (check(mid) == k)
	 	{
	 		minn = min(minn, mid), maxn = max(maxn, mid); 
	 		r = mid - 1;
 	 	}
 	}
 	l = 1LL, r = 1000000000000LL;
 	while (l <= r)
 	{
 		int mid = (l + r) >> 1;
 		if (check(mid) > k)//如果最终的结果比k大,n越大,k越小 
 			l = mid + 1;
 	 	if (check(mid) < k)
 	 		r = mid - 1;
 	 	if (check(mid) == k)
 	 	{
 	 		minn = min(minn, mid), maxn = max(maxn, mid); 
 	 		l = mid + 1;
 	 	}
 	}
 	if (minn == 2147483647124544)
 		printf("-1"), exit(0);
 	printf("%lld %lld", minn, maxn);
 	return 0;
}	
原文地址:https://www.cnblogs.com/liuwenyao/p/11715574.html