[Pregunta Solución] Luogu P1182 Secuencia Sección II (Explicación detallada de la respuesta de dos puntos)

Ir a: Mi propio blog

tema

Luogu P1182 Serie Sección II

responder

Esta pregunta necesita usar la dicotomía, pero en lugar de buscar un valor en una secuencia monótona en el sentido tradicional, la respuesta de la dicotomía se transforma en un juicio, que es más abstracto. Primero, defina "si la secuencia se puede dividir en m segmentos, y la longitud de cada segmento es menor o igual que la suma, entonces la suma se llama valor legal", entonces se requiere el valor legal mínimo en la pregunta. Fácil de probar: cuanto mayor es la suma, más fácil es ser legal y hay un valor límite s. La suma menor que s no es legal, y la suma mayor o igual as es legal (s es el valor requerido por el título). El valor legal se denomina "1" y el valor ilegal se denomina "0". Luego está la siguiente secuencia para la suma de menor a mayor: …… 0000011111 ……. Si la legalidad se verifica uno a uno de pequeño a grande o de grande a pequeño, la velocidad es más lenta, así que considere la dicotomía. Los punteros izquierdo y derecho de la dicotomía son lyr, mid = (l + r) / 2, todos representan el valor de la suma. Si mid es un valor legal, s está a su izquierda o él mismo, entonces el rango de búsqueda se puede reducir de [l, r] a [l, mid]; si mid es un valor ilegal, s está a su derecha, y el rango está determinado por [ l, r] se reduce a [mid + 1, r].

Hablemos de cómo realizar pruebas de legalidad: simplemente sé codicioso. Dividir de izquierda a derecha, con tantos segmentos como sea posible, si el número de segmentos al final es menor o igual que m, es 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;
}

Supongo que te gusta

Origin blog.csdn.net/zjgmartin/article/details/108415813
Recomendado
Clasificación