Codeforces 83B Docter (二分)

5 篇文章 0 订阅

https://blog.csdn.net/a540524095/article/details/51984698

二分查找每个人最多看几次病后,时间结束

通过二分法来获得最后每个人最多看?(middle)次
即最后看完的那个人(lucky dog)的被看的次数
当num[i]<middle时,那么第i个一定已经看完病了。
lucky dog也不一定看完了病
①如果lucky dog看完病了,
那lucky dog之前num[i]=middle的病人和lucky dog,一样幸运,看完了病。
那lucky dog之后num[i]=middle的病人就没有lucky dog那么幸运。还差一次才能看完
num[i]>middle的病人是一定看不完病的。
②lucky dog 没有看完病
那么num[i]>=middle(包括lucky dog)是看不完病的。

轮一遍病人的序列,sum=middle*n
当num[i]<k时,这个人有(middle-num[i])次看病为假,middle*n减去middle和num[i]的差值
剩下的是sum,超过k的部分为假。
也有可能刚刚等于K,此时看病次数和lucky dog相同的病人全部看完
sum>=k;
 

#include<stdio.h>
#define maxn 100000
long long patient[maxn+10];
long long answer[maxn+10];
int main()
{
    long long n,k,sum=0,maxi=0;
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&patient[i]);
        sum+=patient[i];
        if(maxi<patient[i])
            maxi=patient[i];
    }
    if(sum<k)
    {
        printf("-1\n");
        return 0;
    }
    else if(sum==k)
    {
        return 0;
    }
    long long left,right,middle,times,where,ans;
    left=0;
    right=maxi;
    while(left<=right)
    {
        middle=(left+right)/2;
        //printf("\nleft=%lld right=%lld middle=%lld\n",left,right,middle);
        times=middle*n;
        for(long long i=1;i<=n;i++)
            if(patient[i]<middle)
                times-=(middle-patient[i]);
        //printf("times=%lld k=%lld\n",times,k);
        if(times>=k)
        {
            ans=middle;
            right=middle-1;
        }
        else if(times<k)
        {
            left=middle+1;
        }
    }
    //printf("********ans=%lld\n",ans);
    for(long long i=1;i<=n;i++)
    {
        if(ans>patient[i])
        {
            k-=patient[i];
            patient[i]=0;
        }
        else
        {
            k-=(ans-1);
            patient[i]-=ans-1;
        }
    }

    int i=1;
    while(k>0)
    {
        if(patient[i]>0)
        {
            patient[i]--;
            k--;
        }
        if(k==0)
            where=i;
        i++;
    }
    int cnt=0;
    for(long long j=where+1;j<=n;j++)
    {
        if(patient[j]>0)
            answer[cnt++]=j;
    }
    for(long long j=1;j<=where;j++)
    {
        if(patient[j]>0)
        {
            answer[cnt++]=j;
            //printf("answer[%d]=%lld\n",cnt-1,answer[cnt-1]);
        }

    }
    for(long long j=0;j<cnt;j++)
        if(j!=cnt-1)
            printf("%lld ",answer[j]);
        else
            printf("%lld\n",answer[j]);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值