[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 审核没过,将叙述改的更详尽一些

posted @ 2023-02-15 19:05  Tsawke  阅读(26)  评论(0)    收藏  举报