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;
}