二分初体验

版权声明: https://blog.csdn.net/qq_40828060/article/details/82112253

目录

P2678 跳石头

这题一开始没读懂题,后来发现实际上是个类似贪心的思想
大意是说,每种移石子的方案都会有一个最小的距离,然后要求这其中的最大距离
也就是喜闻乐见的最小值最大
暴力枚举每种方案的复杂度是O(n^m),铁定会挂
我们自然会想到枚举每种答案再判断是否合法
而二分就是一种优化枚举答案次数的算法,复杂度O(nlogn),十分优秀
具体做法是二分答案,然后判断
由于读入是单调的,就省去了排序
判断的具体过程就是看这个解是否合法,简单来说就是模拟跳石子的过程看看是否符合题意
如果合法,考虑到答案不一定最优,继续往下找
如果不合法,由于序列是单调递增的,因此当前不合法后面的一定也不合法,因此往前找
这里给出上一行的证明
不合法说明撤掉的石子m1>m才能使答案成立,如果答案更大,则需要更大的m2>=m1,所以m2显然>m,不合法

这里其实还有个贪心的思想
可以把前缀和排序,然后尽量移除最小的(类似合并果子的操作),然而复杂度是爆炸的

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int const maxn=60000;
int a[maxn];
int d,n,m,l,r,ans;

int judge(int ans)
{
    int next=1,now=0,cnt=0;
    while(next<=n+1)
    {
        if(a[next]-a[now]<ans)
            cnt++;
        else
            now=next;
        next++;
    }
    if(cnt>m)
        return 0;
    return 1;
}
int main()
{
    scanf("%d%d%d",&d,&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    a[n+1]=d;
    l=1,r=d;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(judge(mid))
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    printf("%d",ans);
    return 0;
}
好了我总算知道二分答案的真谛了= =
所谓二分答案其实是二分最优的满足某种性质的值(最优&&可行),然后验证他是否符合这种性质即可,比如最小值最大就是二分最大,验证是否符合最小
综上所述,能进行二分答案的条件
答案可以验证(比如模拟等等)
答案范围小(满足nlogn的复杂度)

CodeVS 2072 分配房间

这题和跳石头还不一样= =
这题必须要先选一个
因此边界处理不同

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int const maxn=1000101;
long long n,m,l,r,a[maxn],ans;

int check(int ans)
{
    int last=1,cnt=m-1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]-a[last]>=ans)
        {
            cnt--;
            last=i;
        }
    }
    if(cnt<=0)
        return 1;
    return 0;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    sort(a+1,a+1+n);
    l=0,r=a[n]-a[1];
    //在这出了锅 
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    printf("%lld",ans);
    return 0;
}

好了二分答案又一关键:初始化、边界问题
这个无法总结,具体题目具体分析吧

CodeVs 1725探险

这题没啥好说的,一眼就看出来怎么做了
就是边界调了好久…
还是手模靠谱

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int const maxn=1000110;
int n,m,a[maxn],prs[maxn],l,r,ans;

inline int check(int ans)
{
    int cnt=0,last=0;
    for(int i=1;i<=n;i++)
        if(prs[i]-prs[last]>=ans)
        {
            cnt++;
            last=i;
        }
    if(cnt>=m)
        return 1;
    return 0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        prs[i]=a[i]+prs[i-1];
//      printf("%d\n",prs[i]);
    }
    l=0,r=prs[n];
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))
        {
            ans=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    printf("%d",ans);
    return 0;
}
//又又又栽在初始化上了QAQ,以后绝对不能臆想了,还是手模靠谱... 

P1083 借教室

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int const maxn=1000110;
int n,m,a[maxn],dlt[maxn],x[maxn],y[maxn],l,r,c[maxn],ans;

inline int check(int h)
{
    memset(c,0,sizeof(c));//每次都要把差分数组还原 
    int sum=0;
    for(int i=1;i<=h;i++)
    {
        c[x[i]]+=dlt[i];
        c[y[i]+1]-=dlt[i];//边界问题 
    }
    for(int i=1;i<=n;i++)
    {
        sum+=c[i];
//      prs[i]=prs[i-1]+c[i];
    //我曾经是这么写的,但总感觉不对
    //好吧我蠢了
    //prs[1]=prs[0]+c[1]就相当于初始化了== 
        if(sum>a[i])
            return 0;
    }
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&dlt[i],&x[i],&y[i]);
    l=0,r=m;
    if(check(r))
    {
        printf("0");
        return 0;
    }
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))
            l=mid+1;
        else
        {
            ans=mid;
            r=mid-1;
        }
    }
    printf("-1\n%d",ans);
    return 0;
}
//答案到底是mid还是mid+1傻傻分不清楚== 
//好吧是我自己的锅,ans应该在订单超出时赋值 

猜你喜欢

转载自blog.csdn.net/qq_40828060/article/details/82112253
今日推荐