洛谷2678 跳石头

洛谷2678 跳石头


原题链接


交题记录

22:28 AC


题解

这次做这个题主要是为了填一下二分答案的坑。。。
由于某些细节问题处理不当一直没写出来。。。。。
现在终于搞清楚了。。。
以后去多做几道相关的题。。。

二分答案,我理解为通过二分的方式来求得答案,以代替枚举,将\(O(n)\)枚举降到\(O(log_2n)\)枚举
条件?满足单调性,即是否可行与决策的关系是这样的:
1111111111111110000000000000000000000
0000000000000000001111111111111111111111
111110000
01111111111111
而不是这样的:
010000000000000000
1000000000000000010
等等。
只要\(i\)可行,所有\(j>i\)\(j<i\))也都可行。
如何枚举?设l,r,表示答案只会在\([l,r]\)中出现。
核心:check函数
当然也可以写成别的。
当check返回1时,视为可行,返回0时,不可行。当然可以根据喜好改变
按上面来。假设只要\(i\)可行,所有\(j<i\)也都可行(也就是本题的形式)。

while(l<r){
    mid=l+r>>1;
    if(check(mid+1))l=mid+1;
    else r=mid;
}

二分答案有很多版本,随便了。。。
我用上面的模板
\([l,r]\)中取一个\(mid\)并对\(mid+1\)进行check(为什么?因为mid向下取整,如果l=1,r=2就会一直死循环下去)
mid+1可行:l=mid+1.因为\([1,mid+1]\)都可行,此时\(mid+1\)更优
mid+1不可行:后面都不可行,r=mid.


Code

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=50010,maxm=maxn<<1;
int d[maxn],L,n,m;
il bool check(int ans){
    int last=0,sum=m;
    rep(i,1,n)
        if(d[i]-last<ans){
            if(sum)--sum;
            else return 0;
        }
        else last=d[i];
    return 1;
}
int main(){
    L=gi(),n=gi()+1,m=gi();
    rep(i,1,n-1)d[i]=gi();
    d[n]=L;
    int mid,l=1,r=L;
    while(l<r){
        mid=l+r>>1;
        if(check(mid+1))l=mid+1;
        else r=mid;
    }printf("%d\n",l);
    return 0;
}

没了。。。

posted @ 2017-08-24 22:45  菜狗xzz  阅读(189)  评论(0编辑  收藏  举报