[Question Solution] Luogu P1182 Sequence Section II (Detailed explanation of two-point answer)

Go to: My own blog

topic

Luogu P1182 Series Section II

answer

This question needs to use the dichotomy, but instead of looking for a value in a monotonic sequence in the traditional sense, the dichotomy answer is transformed into a judgment, which is more abstract. First, define "if the sequence can be divided into m segments, and the length of each segment is less than or equal to sum, then sum is called a legal value", then the minimum legal value is required in the question. Easy to prove: The larger the sum is, the easier it is to be legal, and there is a boundary value s. The sum less than s is not legal, and the sum greater than or equal to s is legal (s is the value required by the title). The legal value is referred to as "1", and the illegal value is referred to as "0". Then there is the following sequence for sum from small to large:……0000011111……. If the legality is verified one by one from small to large or from large to small, the speed is slower, so consider dichotomy. The left and right pointers of the dichotomy are l and r, mid=(l+r)/2, they all represent the sum value. If mid is a legal value, s is on its left or itself, then the search range can be reduced from [l,r] to [l,mid]; if mid is an illegal value, s is on its right, and the range is determined by [ l,r] is reduced to [mid+1,r].

Let's talk about how to conduct legality testing: just be greedy. Divide from left to right, with as many segments as possible. If the number of segments at the end is less than or equal to m, it is legal.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int m,n;
ll a[maxn];
inline bool check(ll sum)	//判断每段长度<=sum是否可行 
{
	ll now=0,cut=1;	//now表示当前段已有长度,cut表示当前是第几段(注意初始值是1,不是0) 
	for(int i=1;i<=n;i++)
	{
		if(a[i]>sum) return 0;	//注意这种情况 
		if(now+a[i]>sum)
		{
			if(cut==m) return 0;
			now=a[i];
			cut++;
		}
		else now+=a[i];
	}
	return 1;
}
inline ll erfen()
{
	ll l=0,r=0;
	for(int i=1;i<=n;i++) r+=a[i];
	while(l<r)
	{
		ll mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1; 
	}
	return l;
}
		
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	printf("%lld\n",erfen());
	
	return 0;
}

Guess you like

Origin blog.csdn.net/zjgmartin/article/details/108415813