zoukankan      html  css  js  c++  java
  • 题解 P2678 【跳石头】

    这道题很显然是用二分法,大部分人也是这么做的,但是有个问题大家都没注意到,就是二分的初始范围。

    二分范围的上限

    由于移走了M块岩石,所以还剩下N-M块岩石,将河道分割成了N-M+1个部分,设最短跳跃距离为D,则

    D×(N-M+1)<=L

    即 D <= L / (N-M+1)

    所以最短跳跃距离的最大值= L / (N-M+1)

    二分范围的下限

    令D1为初始距离的第M+1小值,即初始时一共有M个距离小于D1,由于两个相邻的岩石产生一个距离,对于每个小于D1的距离,任选其两侧的岩石之一取走,这样每取走一个岩石,小于D1的距离就会少一个,取走M个岩石后,岩石之间的最小距离必然 >=D1,可能这句话不好理解,我以一个具体的例子解释一下。

    0(7)1(1)2(3)3(4)4(5)5(6)6(2)7(8)8

    0、8代表了两端点,1、2、···7代表了7块岩石,括号里的数字代表了岩石之间的距离。假设M=2,则初始距离的第M+1小值为3(2、3岩石之间的距离),比3距离小的距离为1(1、2岩石间)和2(6、7岩石间)。若取走的2个石头是1、2岩石中的一个,6、7岩石中的一个,则距离1和2都不存在了,每取走一个石头,小于D1的距离就少一个,所以最短跳跃距离的最小值必然 >=D1。 即二分初始范围的下限为距离中第M+1小值。

    之后的做法就是二分法了,附上AC代码

    #include<bits/stdc++.h>
    #include<math.h>
    using namespace std;
    void quickSort(int* a, int l, int r)
    {
        if (l < r)
        {   int i, j, x;
            i = l;
            j = r;
            x = a[i];
            while (i < j)
            {
                while (i < j && a[j] > x)
                    j--;
                if (i < j)
                    a[i++] = a[j];
                while (i < j && a[i] < x)
                    i++;
                if (i < j)
                    a[j--] = a[i];
            }
            a[i] = x;
            quickSort(a, l, i - 1);
            quickSort(a, i + 1, r);
        }
    }
    int main()
    {
        int l, m, n, i, a[50000], c[50001], d, e, mid, f = 0, g = 0;
        cin >> l >> n >> m;
        d = l / (n - m + 1);
        for (i = 0;i <= n - 1;i++)
        {
            cin >> a[i];
        }
        a[n] = l;
        c[0] = a[0];
        c[n] = l - a[n - 1];
        for (i = 1;i <= n - 1;i++)
        {
            c[i] = a[i] - a[i - 1];
        }
    
        quickSort(c, 0, n);
        e = c[m];
        while (e + 1 < d)
        {
            g = 0;
            f = 0;
            mid = (e + d) / 2;
            i = 0;
            while (1)
            {
                while (i <= n && a[i] - g < mid)
                {
                    f++;
                    i++;
                }
                if (i >= n) break;
                if (i < n)
                {
                    g = a[i];
                    i++;
                }
    
            }
            if (f <= m)
            {
                e = mid;
            }
            else d = mid;
        }
        cout << e;
        return 0;
    }
  • 相关阅读:
    [转]直接拿来用!最火的Android开源项目(一)
    [原] jQuery EasyUI 1.3.2 离线API、Demo
    [原]通过GitHub Pages建立个人站点(详细步骤)
    [转]直接拿来用!最火的Android开源项目(二)
    堆排序
    单例模式
    【面试题】:火车运煤问题
    Aptana Studio 2.0 对JQuery的智能提示的支持
    vs2005 常用快捷键(备忘)
    关于ASP.NET在IIS上的一些问题的解决办法
  • 原文地址:https://www.cnblogs.com/lau1997/p/15603567.html
Copyright © 2011-2022 走看看