zoukankan      html  css  js  c++  java
  • luogu2678 跳石子 二分

    题目大意:

    一个赛道上除起点、终点外有(N)个点。现要求你从中删除(M)个点,使得剩余点序列中相邻的点的最小值最大。求这个最大的最小值。

    思路

    我们最容易想到的算法便是:对序列从头到尾循环(M)次,每次把间距最小的一对点删除其中一个,删除的那一个点到两边的点的距离之和应当是相对小的那一个。但是代码具体实现怎么做?而且时间复杂度也太高了!此时我们应当直接换切入点,而不是想方设法在这个思路上寻找解决方法。
    题中要我们求的是,而值的范围由起点和终点不改变已经是有限了。而且显然要求的这个最小值越大,要删去的点不变或越多,否则不变越少。于是我们就可以对要求的最大的最小值进行UpperBound二分了。
    那么对于一个潜在的值mid,如何得知要想使剩余点序列中相邻的点的最小值至少为(m)要删去多少个点呢?问题就在于,如果我们知道一对相邻点距离小于mid,我们是删除左面的点还是右面的点。贪心告诉我们删除右面的点,因为删除右边的点r会影响到更右边的点r',它若不删去r则它与相邻的点的距离小于mid,那么它更可能不用删去它本身而满足条件,而删除左面的点达不到这样的效果。

    //#define _DEBUG//DELETE!!!!!!!!!!!!!!!
    
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX_P = 50010;
    int P[MAX_P];
    int N, M, L;
    
    bool CanDelInM(int x)
    {
        int lastPos = 0, cnt = 0;
        for(int i=1; i<=N+1; i++)
        {
            if(P[i] - lastPos < x)
                cnt++;
            else
                lastPos = P[i];
        }
        return cnt <= M;
    }
    
    
    int UpperBound(int l, int r, bool (*GreaterOrEqual)(int))
    {
        while(r > l)
        {
            int mid = (l + r + 1) / 2;
            if(GreaterOrEqual(mid))
                l = mid;
            else
                r = mid - 1;
        }
        return l;
    }
    
    int main()
    {
        scanf("%d%d%d", &L, &N, &M);
        for(int i=1; i<=N; i++)
            scanf("%d", P + i);
        P[N+1]=L;
        sort(P+1, P+N+1);
        printf("%d
    ", UpperBound(1, L, CanDelInM));
        return 0;
    }
    
    
  • 相关阅读:
    Marshal Code Into Another Thread(STAThread)
    MongoDB分片实战(二):Sharding
    项目中如何添加CorePlot开源框架(重温Xcode链接静态库)
    Xcode4.2中将Three20开源库导入到工程项目中
    Ajax在MVC中的使用
    位枚举的学习
    MVC3+NHibernate项目实战(二) :数据库访问层
    MVC3+NHibernate项目实战(一) :项目设计
    Android VideoView
    00设计原则
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9094533.html
Copyright © 2011-2022 走看看