P2678 [NOIP2015 提高组] 跳石头

原题链接-P2678 [NOIP2015 提高组] 跳石头

        刚看到这个题时,相信有很多小伙伴和本蒟蒻一样——循环找出最小值,然后不断丢掉两端距离相对较小的石头,最后石头剩下N-M个时,直接输出最小间距。但是如此暴力的做法,终究会迎来残酷的结局——TLE*n……然后打开题目标签一看“贪心”“二分”,其中贪心很好理解嘛,尽量把小的间距全部去掉,留下的自然就大了;至于二分,本蒟蒻是个笨蛋,理解了好久才明白如何利用二分解答此类问题。

        二分的大前提是找到左边界(min)和右边界(max),在这个题里,很明显你可以直接min=1,max=L来操作,实际上也确实能够AC,但是稍微思考一下,就会发现max其实并不是每次都能取到L,而是max=L/(N-M+1)。因为河里面至少有N-M块石头,那么就有N-M+1个间距,要取最大间距只能是石头按某一间隔均匀放置,所以就得到了max=L/(N-M+1)

        找完边界了,接着来判断二分的条件。这里我写了一个check函数,判断最小间距取mid是否合适。如果check(mid)==1,那么就说明这个mid满足条件,我们可以用ans记录该值,然后往mid+1-max这个区间继续找更符合(更大)的值;如果check(mid)==0,则说明mid不满足条件,得在min-mid-1中继续寻找合适的答案。最后当max<min时退出循环,输出ans即可。

        本蒟蒻AC代码如下:


#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
int m, n, l, a[N], t[N];
bool check(int x)
{
    int num{}, p{};
    for (int i = 1; i <= n + 1; i++)//复制a数组给t,因为t每check一次都会改变
    {
        t[i] = a[i];
    }
    for (int i = 1; i <= n + 1; i++)
    {
        if (t[i] - t[i - 1] < x)
        {
            t[i] = t[i - 1];
            num++;
        }
    }
    return num <= m;
}
int main(void)
{
    cin >> l >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    a[n + 1] = l;
    int max{l / (n - m + 1)}, min{1}, mid{}, ans;
    while (max >= min)//二分寻找最优答案
    {
        mid = max + min >> 1;
        if (check(mid))
        {
            ans = mid;
            min = mid + 1;
        }
        else
        {
            max = mid - 1;
        }
    }
    cout << ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一片在学code的小枫叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值