灵感来自帅气的yk!
题目来源:链接
土豆片经过上周搜索专题的摧残,在椒盐粉的安慰和支持下艰难的挺到了这周,二分专题又出现了.......
看土豆片二分的开端一题!(成熟土豆片,不止会用暴力!)
题目:
土豆片der思考:
二分的起源之路:
首先,如果我们在不知道这是二分专题的情况下如何能联想到是要使用二分来写的捏?
经过土豆片的潜心研究发现(其实基本上都是从大神那看的)题目都会有以下特征:
1.数组元素一定会按照某种顺序排列或可以按照某顺序排列后进行处理(数组有序)
2.数据范围较大不能使用传统艺能——暴力遍历,并且答案范围在一个区间内(答案有界)
另外什么时候用二分答案:
如果题目规定了有“最大值最小”或者“最小值最大”的东西。如本题“选手们在比赛过程中的最短跳跃距离尽可能长”就显然满足此特征。
题目思路:
首先,石头距离是有序,我们确定一个距离mid,从左往右开始判断,如果距离小的就移除并计数+1,反之就向前跳到下一个,最后看如果所有移走的石头数量大于能够移走的数量则答案在左侧,反之在右侧,.
显然,数据范围不允许土豆片进行遍历寻找mid,所以此题就是对距离mid进行二分寻找答案,
时间复杂度:O(能过)
额....(土豆片不会算,好心的大佬可以评论说一下)
可能出现的问题:
(由高冷白熊提出)
会不会少判断最后一个石头?
帅气土豆片自信回答:在进行移动时是先进行判断再移动,在最后的n时只需跳到终点,不用移走石头,也没有石头可以移走,至于到n时,是在第n-1上就判断过,所以是不会少判断数据。
起源之路的神奇钥匙(答案):
#include<bits/stdc++.h>
#define int long long //土豆片太懒的写法
using namespace std;
int a[50005],l,r,ans;
int len,n,m;
bool bluechips_check(int x){
int rock=0,num=0,now=0; //rock表示要移除的石头,num表示现在要继续判断的石头
while(num<=n){ //now表示现在站的石头
num++;
if(a[num]-a[now]<x){ //灵魂判断 如果小于这个答案就代表需要移除
rock++;
}else{
now=num; //如果不小于就表示可以跳到这里
}
}
if(rock<=m){
return true;
}else{
return false; //要搬走的大于最大m就不行说明太大
}
}
signed main(){
cin>>len>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
a[n+1]=len; //输入位置并将最后的岸边作为最后一个位置
l=0;
r=len;
while(l<=r){
int mid=(l+r)/2; //二分板子(土豆片是背的不会解释)
if(bluechips_check(mid)){
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
cout<<ans;
}
总结:
1.二分的特征与板子
2.二分答案的使用情况(文中都有说明)
感谢提供灵感的帅气yk和高冷白熊*★,°*:.☆( ̄▽ ̄)/$:*.°★*
完结*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。