【二分答案】 HDU 5248 序列变换

闲着没事干想写一篇关于简单二分的解析

题意:

 

思路:

求最值一般有三种思路:

贪心

二分

Dp

这道题用二分答案

我们考虑把最小代价二分出来

能使用二分的前提是单调性

在这道题中,如果代价足够大(先假设代价是无穷大),那么A数组变成B数组就没有任何限制,一定可以变成B数组

然后,考虑把代价减小一点点(但是仍然是很大),A数组还是很有可能变成B数组,因为此时限制还是很小,能使用的代价还是很多

继续减小这个代价,极端地考虑,减到0,此时A数组一定不能变成B数组,因为此时能供你使用的代价为0,A数组不能作任何改变

那么,这个代价从无穷大减小到无穷小的过程中,一定存在某一点,使得它刚好从“能变成B数组”变成“不能变成B数组”

我们要求的就是这个“临界点”,这个“临界点”就是最小代价

与其说是最小代价,其实是指:求最大代价的最小值

像这种求最大的最小值,或求最小的最大值,一般都是用二分答案做

这个0表示不能把A数组变成B数组

1表示可以

X就是我们要求的临界点

如果二分出来的是0,那么l=mid+1;

如果二分出来的是1,那么r=mid-1;

那么我们二分出来一个值后,如何判断它是1还是0?

假设我们二分出代价 x ,我们去判断这个 x 够不够将A数组变成B数组

在这个判断过程中,一般要用到贪心的思想

要让A数组更容易变成B数组,A数组一定是越小越好

因此我们先将a[1]-=x,第一个数变小之后,因为是严格递增的,后面的数也可以相应地变小

然后我们去考虑后面的数

如果a[2]比a[1]小且a[2]<a[1]-x,即a[2]+x<a[1](x为二分出来的代价),那么a[2]就不能变成比a[1]大的数,直接return false即可,

如果a[2]比a[1]小且a[2]>=a[1]-x,即a[2]+x>=a[1](x为二分出来的代价),那么a[2]只要加上x就能变成a[1],因此将a[2]变成a[1]+1就好了,(因为要让A数组尽可能小而又要满足严格递增,贪心的思想)

如果a[2]比a[1]大且a[2]>a[1]+x,即a[2]-x>a[1](x为二分出来的代价),那么要让A数组尽可能小,就让a[2]-=x;

如果a[2]比a[1]大且a[2]<a[1]+x,即a[2]-x<a[1](x为二分出来的代价),那么要让A数组尽可能小,就让a[2]变成a[1]+1即可

后面的a[i]都可以从a[i-1]这样递推而来

#include <bits/stdc++.h>
using namespace std;
const int mxn=1e5+10;
int n,ans,T=0;
int a[mxn],b[mxn];
bool check(int x){//判断二分出来的值是0还是1
    memcpy(b,a,sizeof(b));//为了不破坏a数组,设一个新的b数组,从a数组那边复制过来
    b[1]-=x;
    for(int i=2;i<=n;i++){
        if(b[i]<=b[i-1]){
            if(b[i]+x>b[i-1]) b[i]=b[i-1]+1;
            else return false;
        }else if(b[i]-x>b[i-1]) b[i]-=x;
        else b[i]=b[i-1]+1;
    }
    return true;
}
void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int l=0,r=1e9;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)){
            ans=mid;
            r=mid-1;
        }else l=mid+1;
    }
    printf("Case #%d:\n%d\n",++T,ans);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值