[ABC270E] Apple Baskets on Circle
[ABC270E] Apple Baskets on Circle Solution
更好的阅读体验戳此进入
题面
存在 $ n $ 个筐围成一圈,第 $ i $ 个有 $ A_i $ 个苹果。你需要从第 $ 1 $ 个筐开始依次拿掉一个苹果,直到拿了 $ k $ 个。如果筐内没有苹果那么直接拿下一个筐。求最终每个筐里还剩多少个苹果。
Solution
题解区怎么都是二分答案的做法,来一发 VP 时糊出来的更加无脑的模拟做法。
首先假设一圈里有 $ k $ 个篮子里有苹果,那么转一圈一定会拿走 $ k $ 个苹果,然后当拿空了一个篮子之后就会 $ k \leftarrow k - 1 $。所以我们考虑维护一下当前一共还有多少个篮子里有苹果,然后给所有 $ A_i $ 排个序,每次取最小的然后判断是否能拿空,如果可以的话那么直接拿空,否则尽量拿多圈,此时剩下的所有显然不足一圈,此时再次遍历一遍即可。
然后注意其中有一步 $ cur \times v $,这个东西我感觉似乎是 $ 10^{24} $ 级别的,于是开了个 __int128_t
。
审核没通过,说太简略了,那么就把具体过程再说一下吧:
维护一个 $ minus $ 表示当前一共拿过了多少圈,每次取一个苹果数最小的篮子并去掉已经拿走的 $ minus $ 个,然后考虑现在剩下的有苹果的篮子数,即 $ cur $ 乘上最小的剩的苹果数,如果可以全部取走那么就都取走,然后 $ minus \leftarrow minus + v $。反之尽量拿更多圈,记录剩余多少个苹果没拿,显然其会小于剩余的存在苹果的篮子数,此时暴力枚举跑一下即可。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N; ll K;
ll A[210000];
priority_queue < ll, vector < ll >, greater < ll > > buc;
int main(){
N = read(), K = read < ll >();
ll cur(0);
for(int i = 1; i <= N; ++i)if((A[i] = read < ll >()))buc.push(A[i]), ++cur;
ll minus(0);
while(!buc.empty()){
ll v = buc.top() - minus; buc.pop();
if((__int128_t)cur * v <= K)K -= cur * v, minus += v, --cur;
else{minus += K / cur, K -= K / cur * cur; break;}
}
for(int i = 1; i <= N; ++i)A[i] = max(0ll, A[i] - minus);
for(int i = 1; i <= N && K; ++i)if(A[i])--A[i], --K;
for(int i = 1; i <= N; ++i)printf("%lld%c", A[i], i == N ? '\n' : ' ');
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2023_01_27 初稿
update-2023_02_01 审核没过,将叙述改的更详尽一些