一、思路
有点难想的二分啊,由于每个石头间的间隔大小是逐渐递增的(单调的),且有最大间隔:
L/(n-m),所以可以二分出选择的最小间隔,并依次来卡石头的数。若直接贪心,则时间复杂度是n方,而这样就是nlogn。所以不会TLE
#include<bits/stdc++.h>
using namespace std;
int L, N, M;
int arr[50009] = { 0 };//数组储存的是每个石头的间隔
int main()
{
scanf("%d%d%d", &L, &N, &M);
int left = 0, right = 0;
for (int i = 0; i < N; i++)
{
scanf("%d", &right);
arr[i] = right - left;//边输入边存间隔
left = right;
}
arr[N] = L - left;
if (N == M)//边界条件判断,下面除法的分母不为0,即把石头全拿走时的情况
{
printf("%d", L);
return 0;
}
else
{
right = L / (N - M);//最小间隔可能的最大值
left = 0;//最小值
while (left + 1 != right)//二分
{
int mid = (left + right) / 2;
int count = 0;//计算移动石头的总数
for (int i = 0; i <= N; i++)
{
int temp = arr[i];
while (temp <= mid)//间隔的合并操作
{
i++;
count++;
if (i > N)//这里要写在count++的后面,否则会漏掉对最后一个石头的判断
{
break;
}
temp = temp + arr[i];
}
}
if (count <= M)
{
left = mid;
}
else
{
right = mid;
}
}
}
int min = L;//左边界并非最小值,而是要去除的边界值,因此再判断一遍题目中现存的最小值
for (int i = 0; i <= N; i++)
{
int temp = arr[i];
while (temp <= left && i < N)
{
i++;
temp = temp + arr[i];
}
if (temp > left && temp < min)
{
min = temp;
}
}
printf("%d", min);//输出最小值
//printf("%d", left);
return 0;
}