Bootstrap

Bridging the Gap2 (2024牛客多校3 A)

Bridging the Gap2

题目大意


共有 n ( 1 ≤ n ≤ 5 × 1 0 5 ) n(1 \le n \le 5 \times 10^5) n(1n5×105)个人处在河的一侧,现在有一艘船,船上只能容纳 k k k个人, k ∈ [ l , r ] k \in [l, r] k[l,r]。问能否将所有人送至河的另一侧。

解题思路


假设这 n n n个人一开始处在河的左侧,可以推出,从左侧划船至右侧在整个过程中是一定可行的。

因为,每次从右侧划回来都至少会带回 l l l个人,那么左侧人数一定始终大于 l l l,并且他们的体力也一定大于等于 1 1 1,要将所有人送至右侧,自然不会让划回左侧后没体力的人回来,所以从右侧回来的人体力一定大于等于 1 1 1,原本留在左侧的人体力也一定大于等于 1 1 1

所以,我们只需要保证整个过程中,每次都至少有 l l l个人能从右侧划回左侧,并且他们的体力大于等于 2 2 2

那么首先,我们算出整个过程中从右侧返回左侧的总次数, S = ⌈ n − r r − l ⌉ S = \lceil\frac{n - r}{r- l}\rceil S=rlnr,即第一次划向右侧会使左侧减少 r r r个人,接下来每个来回都会使左侧减少 r − l r - l rl 个人,最后上取整即可。

接下来算出每个人最多能从右侧返回左侧多少次, a i = m i n ( ⌊ h i − 1 2 ⌋ , S ) a_i = min(\lfloor\frac{h_i - 1}{2}\rfloor, S) ai=min(⌊2hi1,S),即第一次划向右侧后,剩下的体力值能划几个来回,由于将所有人都送至对岸的次数为 S S S次,所以还要与 S S S m i n min min

将所有人送至河的另一侧等价于每次都至少有 l l l个人能从右侧划回左侧,即 S l Sl Sl,最后只需要与 ∑ a i \sum a_i ai做个比较即可。

因为 a i ≤ S a_i \le S aiS,所以每次划回来第 i i i个人只算了一次贡献,如果第 i i i个人体力耗尽,那就再找一个人假设为 j j j,来继续带他完成这 S S S次划船。

所以当 ∑ a i ≤ S l \sum a_i \le Sl aiSl,则可以将所有人送至河的另一侧,反之则不能。

参考代码

#include <bits/stdc++.h>
#define maxn 500100
#define int long long
using namespace std;
const double eps = 1e-8;
int a[maxn];

void solve() {
    int n, l, r, sum = 0, cnt = 0;
    cin >> n >> l >> r;
    sum = (n - r + r - l - 1) / (r - l);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        cnt += min((a[i] - 1) / 2, sum);
    }
    if(cnt >= sum * l)  cout << "Yes\n";
    else  cout << "No\n";
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);  cout.tie(0);
    int t = 1;
    while (t--) {
        solve();
    }
    return 0;
}
;