ABC 270 E - Apple Baskets on Circle(二分)

https://atcoder.jp/contests/abc270/tasks/abc270_e

题目大意:

有n个篮子排列成一个圆圈,每个篮子里面有ai个苹果🍎

高桥从1号篮筐前开始,重复以下动作。

如果他面对的篮子里有一个苹果,拿一个吃了它。然后,不管他现在是否已经吃了一个苹果,继续到紧挨着右边的下一个篮子。

当高桥总共吃了正好K个苹果时,找出每个篮子里剩余的苹果数量。打印n个整数,中间有空格。

第i个整数应该是当高桥总共吃了正好K个苹果时,篮子i中剩余的苹果数。
Sample Input 1 
3 3
1 3 0
Sample Output 1 
0 1 0 

一开始没思路想着能不能暴力枚举,后来发现数据范围这么大,暴力枚举是一定会寄的
转换思路:
我们可以一开始先取总数小于等于k并且最接近k的那个数字,因为每次无论中间是否掺有减到0的情况,我们还是处于同一水平上
如果刚好在某一轮(遍历整个n)结束了总数为k的取值时,直接减去输出
如果还剩下有数量时,就需要再补一轮进行单个相减(可以知道,这一轮上剩下的绝对会<n)
遍历整个数组,可取并且总数不到k的时候依次--,达到总数k输出停止即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PII;
const LL MAXN=1e18;
const LL INF=1e9;
const LL N=5000200,M=2002;
LL n,k,a[N];
bool check(LL x)
{
    LL res=0;
    for(LL i=1;i<=n;i++)
    {
        if((a[i]-x)>=0) res+=x;
        else res+=a[i];
    }
    //找到最接近总数k的那个每次单独所取的数字
    if(res<=k) return true;
    else return false;
}
int main()
{
    cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
    LL T=1;
    //cin>>T;
    while(T--)
    {
        cin>>n>>k;
        for(LL i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        LL l=0,r=1e12;
        LL ans=0;//每一次取的基本量
        while(l<=r)
        {
            LL mid=(l+r)/2;
            if(check(mid)==true)//可以取到那么多
            {
                ans=mid;
                l=mid+1;//下一步往大了取
            }
            else r=mid-1;//取不到那么多
        }
        //cout<<ans<<endl;
        LL flag=0;
        //flag表示每次取完基本量后已经得到的总和
        for(LL i=1;i<=n;i++)
        {
            flag+=min(a[i],ans);
        }
        //只要还没有取到k那么多的话,就需要再来一轮
        for(LL i=1; ;i++)
        {
            //总数不到最终结果并且当前有多余数字的时候,直接取
            if(flag<k&&a[i]>ans) a[i]--,flag++;
            if(flag==k) break;//取完了,直接结束
        }
        for(LL i=1;i<=n;i++)
        {
            cout<<max((LL)0,a[i]-ans)<<" ";
        }
        cout<<endl;
    }
    return 0;
}
posted @ 2022-11-11 14:40  高尔赛凡尔娟  阅读(39)  评论(0编辑  收藏  举报