2024-07-31-ABC364

A - Glutton Takahashi

有N道菜,高桥按顺序依次吃,每道菜是sweet或者salty,如果他连续吃两道甜的,他会感到不舒服,不能再吃别的了,请你计算他能不能吃掉所有的菜。

模拟即可,依次判断一下sweet之前是不是sweet

#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;
    
    std::vector<std::string> S(N);
    for (int i = 0; i < N; i++) {
        std::cin >> S[i];
    }
    for (int i = 1; i < N - 1; i++) {
        if (S[i] == "sweet" && S[i - 1] == S[i]) {
            std::cout << "No\n";
            return 0;
        }
    }
    std::cout << "Yes\n";
    
    return 0;
}

B - Grid Walk

给定一个二维网格,有障碍物,有空地,给定初始位置。
给定移动操作,若移动目标位置为空地则移动,否则留在原地。
问最终位置。

模拟即可

#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int H, W;
    std::cin >> H >> W;
    
    int X, Y;
    std::cin >> X >> Y;
    X--;
    Y--;
    
    std::vector<std::string> C(H);
    for (int i = 0; i < H; i++) {
        std::cin >> C[i];
    }
    
    std::string S;
    std::cin >> S;
    
    for (auto c : S) {
        int nx = X;
        int ny = Y;
        if (c == 'L') {
            ny--;
        } else if (c == 'R') {
            ny++;
        } else if (c == 'U') {
            nx--;
        } else {
            nx++;
        }
        if (0 <= nx && nx < H && 0 <= ny && ny < W && C[nx][ny] == '.') {
            X = nx;
            Y = ny;
        }
    }
    std::cout << X + 1 << " " << Y + 1 << "\n";
    
    return 0;
}

C - Minimum Glutton

有N道菜,第i道菜有甜度Ai和咸度Bi,高桥要安排吃菜的顺序,他会在吃过的甜度大于X或者咸度大于Y时停下,请问他最少吃多少菜才会停止。

满足一个条件即可,所以我们试一遍最大的甜度再试一遍最大的咸度即可。

#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    i64 X, Y;
    std::cin >> N >> X >> Y;
    
    std::vector<int> A(N), B(N);
    for (int i = 0; i < N; i++) {
        std::cin >> A[i];
    }
    for (int i = 0; i < N; i++) {
        std::cin >> B[i];
    }
    
    int ans = N;
    std::sort(A.begin(), A.end(), std::greater<>());
    std::sort(B.begin(), B.end(), std::greater<>());
    
    for (int i = 0; i < N; i++) {
        X -= A[i];
        if (X < 0) {
            ans = std::min(ans, i + 1);
        }
    }
    for (int i = 0; i < N; i++) {
        Y -= B[i];
        if (Y < 0) {
            ans = std::min(ans, i + 1);
        }
    }
    std::cout << ans << "\n";
    
    return 0;
}

D - K-th Nearest

一维坐标,给定n个点,依次回答q个询问。
每个询问给定一个位置,问距离该位置第k近的点的距离是多少。

二分答案距离,用upper和lower检查距离内点的数量。

#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, Q;
    std::cin >> N >> Q;
    
    std::vector<int> a(N), b(Q), k(Q);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i];
    }
    for (int i = 0; i < Q; i++) {
        std::cin >> b[i] >> k[i];
    }
    
    std::sort(a.begin(), a.end());
    
    for (int i = 0; i < Q; i++) {
        int lo = 0, hi = 2E8;
        while (lo < hi) {
            int x = (lo + hi) / 2;
            
            int l = b[i] - x;
            int r = b[i] + x;
            
            int cnt = std::upper_bound(a.begin(), a.end(), r) - std::lower_bound(a.begin(), a.end(), l);
            if (cnt >= k[i]) {
                hi = x;
            } else {
                lo = x + 1;
            }
        }
        std::cout << lo << "\n";
    }
    
    return 0;
}

E - Maximum Glutton

有N道菜,第i道菜有甜度Ai和咸度Bi,高桥要安排吃菜的顺序,他会在吃过的甜度大于X或者咸度大于Y时停下,请问他最吃多少菜才会停止。

顺序其实无所谓,就是问最多吃几道菜。考虑\(dp_{i,j}\)表示吃了i道菜,甜度为j时的最小的咸度,每次考虑一道新菜吃或不吃去更新一下dp,然后最后O(NX)统计一下答案即可,总时间复杂度O(NNX).

#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, X, Y;
    std::cin >> N >> X >> Y;
    
    std::vector dp(N + 1, std::vector<int>(X + 1, Y + 1));
    dp[0][0] = 0;
    
    for (int i = 0; i < N; i++) {
        int A, B;
        std::cin >> A >> B;
        
        for (int c = i; c >= 0; c--) {
            for (int d = X; d >= A; d--) {
                dp[c + 1][d] = std::min(dp[c + 1][d], dp[c][d - A] + B);
            }
        }
    }
    
    int ans = 0;
    for (int i = 0; i < N; i++) {
        for (int x = 0; x <= X; x++) {
            if (dp[i][x] <= Y) {
                ans = std::max(ans, i + 1);
            }
        }
    }
    std::cout << ans << "\n";
    
    return 0;
}

F - Range Connect MST

一共有N+Q个点,下标为1到N+Q,一共有Q此操作,第i次操作给定L,R,C,将编号在LR之间的点都连到N+i号点上,边权为C,所有操作完成后,问图是否连通,如果连通请输出最小生成树。

我们思考如何构建最小生成树:

考虑克鲁斯卡尔,我们将所有的操作按C排序,然后如果LR之间的j点和N+i不在一个连通块内,那么就连上,这是一个显然正确的最朴素的最小生成树解法,

但是容易看出的是,如果我们跑L到R的话,时间复杂度为O(NQlogN),是通过不了的。

聪明的优化方法:首先后Q个点其实没什么用,我们还是在将每一段点相互之间连接成一个集合,并且每一次链接的代价是C,最后前N个点要连成一个集合的话,后Q个其实一定被连上了。那么我们现在转移思路,我们顺序考虑L到R之间每两个相邻的点是否在一个集合内,这样的话时间复杂度其实还是O(NQlogN)。

小技巧:在做并查集的合并操作时,总将较大编号的点作为根,那么我们在循环的时候可以用下面的操作进行编号的跳跃:

for (int x = dsu.find(L[i]); x < R[i] - 1; x = dsu.find(x)) {
            dsu.merge(x + 1, x);
            ans += C[i];
        }

那么此时,LR中在同一个集合里的j就会被跳过,只会合并没有链接的集合,时间复杂度就下降到了O(NlogN)。

#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;
struct DSU {
    std::vector<int> f, siz;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, Q;
    std::cin >> N >> Q;
    
    std::vector<int> L(Q), R(Q), C(Q);
    for (int i = 0; i < Q; i++) {
        std::cin >> L[i] >> R[i] >> C[i];
        L[i]--;
    }
    
    std::vector<int> p(Q);
    std::iota(p.begin(), p.end(), 0);
    std::sort(p.begin(), p.end(),
        [&](int i, int j) {
            return C[i] < C[j];
        });
    
    DSU dsu(N);
    i64 ans = 0;
    for (auto i : p) {
        ans += C[i];
        for (int x = dsu.find(L[i]); x < R[i] - 1; x = dsu.find(x)) {
            dsu.merge(x + 1, x);
            ans += C[i];
        }
    }
    if (dsu.find(0) != N - 1) {
        std::cout << -1 << "\n";
    } else {
        std::cout << ans << "\n";
    }
    
    return 0;
}

posted @ 2024-11-30 23:27  ~清渠~  阅读(0)  评论(0编辑  收藏  举报