跳石头
跳石头
首先这是一道二分答案的题目
在这道题目的时候,我们先学习了解一下二分法,会的老铁可以跳过直接看后面的题解(下面将分为两种):
朴素二分(简单)
时间复杂度:O(logN)
while (left <= right)//这里要=!!!,因为当left=right时;待查区间为一个数时也要判断是否符合目标值,循环的结束条件是left>right
{
int mid = left + (right - left) / 2;//优化,防止溢出
if (……)
{
left = mid + 1;
}
else if (……)
{
right = mid - 1;
}
else
return ……;
}
我的草稿图,可以参考一下(有点乱不要介意哈):
二分模板(万能,但是细节)
时间复杂度:O(logN)
//查找区间左端点的模板
while (left < right)
{
int mid = left + (right - left) / 2;
if (……) left = mid + 1;
else right = mid;
}
//查找区间右端点的模板
while
{
int mid = left + (right - left + 1) / 2;
if (……) left = mid;
else right = mid - 1;//记忆:有-1上面求中点就要+1
}
这里就简单展示一下模板,想要深入了解的看后后面其他博客哈
这里也简单展示一下草稿:
接着进入正题:
1.首先是总体框架思想:
我们要移走石头,移走后最大距离为:
左边界:l = 1;(题目一说L>=1)
右边界:r = L;(终点)
然后我们就要利用这两个边界进行二分(朴素二分就行)出一个最大的距离
然后根据二分出来的距离通过check()函数检查是否合法:
如果合法:先更新为最新结果,再进行二分,看是否有合法的更大的距离;
如果不合法:返回上次最大的合法距离,结束!
2.接着是check()函数的思想:
通过定义一个:
count(用来统计能移走多少石头,最后和我们一开始输入要求移走最多的石头m进行比较,看是否合法)
pos(一开始定义为0,即为起点,利用arr[i] - pos 记录每块石头之间的距离,并且每次更新pos到下一个位置)
最后判断是否合法,是否合法在上面描述了。
下面是AC的代码~
#include <iostream>
using namespace std;
int L,n,m;
int arr[50001];
//check函数用来判断该距离是否合法
bool check(int x)
{
int count = 0;//该距离能移走多少石头
int pos = 0;
for(int i = 1; i <= n; i++)
{
if(arr[i] - pos < x) count++;//小于我们规定的距离,移走石头
else pos = arr[i];
}
return count <= m;
}
int main()
{
cin >> L >> n >> m;
for(int i = 1; i <= n; i++)
{
cin >> arr[i];
}
n++;
arr[n] = L;//记录终点的位置,check函数里面要用到
//利用二分法得出一个距离,再利用check()函数判断是否合法
int l = 1;
int r = L;
int ret = 0;
//求一个点用朴素二分,求区间采用区间二分,本题用是为了二分出一个距离,用朴素二分
while(l <= r)
{
int mid = l + (r - l)/2;
if(check(mid))
{
l = mid + 1;
ret = mid;
}
else r = mid - 1;
}
cout << ret << endl;
return 0;
}