zoukankan      html  css  js  c++  java
  • 洛谷 P2678 跳石头

    首先让我们先学一下二分答案这个东西...

     

    二分答案的准确定义:

    二分答案是指在答案具有单调性的前提下,利用二分的思想枚举答案,将求解问题转化为验证结果。

     

    大体流程:

    首先需要估计答案的上下界,然后不断取区间中点进行验证(这就要求答案的验证应当简单可行),并通过验证结果不断更新答案区间,最终得到答案。不难看出,朴素的枚举验证时间复杂度是O(n)的,而二分可以做到O(logn)

     

    二分答案的特征:

    1.答案具有单调性

    2.二分答案的问题往往有固定的问法,比如:令最大值最小(最小值最大),求满足条件的最大(小)值等。

     

    二分答案的写法:

    1.在单调递增序列a中查找 >= x 的数中最小的一个(即x 或 x的后继):

    1 while (l < r) {
    2     int mid = (l + r) >> 1;
    3     if (a[mid] >= x) r = mid;
    4     else l = mid + 1;
    5 }
    6 return a[l];
    后继

    2.在单调递增序列a中查找 <= x 的数中最大的一个(即x 或 x的前驱):

    1 while (l < r) {
    2     int mid = (l + r + 1) >> 1;
    3     if (a[mid] <= x) l = mid;
    4     else r = mid - 1;
    5 }
    6 return a[l];
    前驱

    关于这两段代码的解释(见下图):

     

    下面这是一个二分答案的模板题(2019 pdoi T3)

    https://www.luogu.org/problemnew/show/P2678


    这是一个二分答案的模板,然后二分答案的题的细节实在是太多了!!!(然后就一直wa ,无法列举..

    (在不知道有二分答案这个东西之前发现自己的思路完全与其相反,自己只是暴力地解出答案,而不是二分枚举答案

    二分答案的核心上面也都讲了,下面直接是AC代码外加部分细节解释:

     1 #include <cstdio>
     2 
     3 inline int get_num(){
     4     int num = 0;
     5     char c = getchar();
     6     while (c < '0' || c > '9') c = getchar();
     7     while (c >= '0' && c <= '9')
     8         num = num * 10 + c - '0', c = getchar();
     9     return num;
    10 }//快读 
    11 
    12 const int maxn = 5e4 + 5;
    13 
    14 int stone[maxn], n, m, L;
    15 
    16 inline int check(int x){
    17     int cnt = 0, last = 0;
    18     for(int i = 1; i <= n; i++){
    19         if(stone[i] - stone[last] < x) cnt++;
    20         //留着这块石头发现最短路径小于mid,则要删去 
    21         else last = i;//留着则更新上一块石头坐标 
    22     }
    23     if(cnt <= m) return 1;//是否合法 
    24     else return 0;
    25 }//检查是否合法 
    26 
    27 int main(){
    28     L = get_num(), n = get_num(), m = get_num();
    29     for(int i = 1; i <= n; i++) stone[i] = get_num();
    30     int l = 1, r = L;//@1
    31     while(l < r){
    32         int mid = (l + r + 1) >> 1;//@2
    33         if(check(mid)) l = mid;
    34         else r = mid - 1;
    35     }//二分答案的核心 
    36     printf("%d", l);
    37     return 0;
    38 }
    AC代码

    解释:

    @1:将r先设到不可能越界的一个位置,然后再进行二分,保证答案在[L,R]这个区间中

    @2:>>1 和 / 2 都是除以二,但是 >> 1 是向下取整, / 2是向零取整,为了避免二分答案中出现负数。这行如果写成这种形式,那么r就直接赋值为L,不要赋值L+1

  • 相关阅读:
    开始准备考研了
    ubuntu安装完vbox没有无缝模式
    Terminator快捷键
    ubuntu启动慢显示waiting for network configuration
    terminal快捷键
    openstack根据软件选择实例resume
    输出数组的全排列
    给非同步的集合加锁原理。
    集合框架—ArrayList的用法
    集合框架 Map的小例子
  • 原文地址:https://www.cnblogs.com/New-ljx/p/10706525.html
Copyright © 2011-2022 走看看