AtCoder Beginner Contest 408

原题链接:AtCoder Beginner Contest 408

目录

A

B

C

D

题意:一个01字符串,每次操作可以一个0变成1,或把1变成0,问将1集中到一起(也可以全是0)的最小次数。


思路:选一段区间,使得区间内0的数量加区间外1的数量和最小。转化为选定区间中0的个数减1的个数的最小值,再加上1的总数。复杂度 \(O(n)\)

#include <bits/stdc++.h>

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

using u128 = unsigned __int128;
using i128 = __int128;

void solve() {
    int N;
    std::cin >> N;
    
    std::string S;
    std::cin >> S;
    
    int cnt = std::count(S.begin(), S.end(), '1');
    int ans = 0;
    int suf = 0;
    for (auto c : S) {
        suf = std::min(0, suf) + (c == '1' ? -1 : 1);
        ans = std::min(ans, suf);
    }
    
    ans += cnt;
    std::cout << ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int T;
    std::cin >> T;
    
    while (T--) {
        solve();
    }
    
    return 0;
}

E

题意:带全图,1到n路径上权值or最小。


思路:
贪心从高位到枚举,缺少哪一位不连通该位一定为1。check感觉能用并查集。复杂度 \(O(n)\)

#include <bits/stdc++.h>

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

using u128 = unsigned __int128;
using i128 = __int128;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, M;
    std::cin >> N >> M;
    
    std::vector<std::vector<std::pair<int, int>>> adj(N);
    for (int i = 0; i < M; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;
        u--;
        v--;
        adj[u].emplace_back(v, w);
        adj[v].emplace_back(u, w);
    }
    
    std::vector<bool> vis(N);
    std::queue<int> q;
    auto check = [&](int s) {
        std::fill(vis.begin(), vis.end(), false);
        vis[0] = true;
        q.push(0);
        while (!q.empty()) {
            int x = q.front();
            q.pop();
            
            for (auto [y, w] : adj[x]) {
                if ((w & s) == w && !vis[y]) {
                    vis[y] = true;
                    q.push(y);
                }
            }
        }
        return vis[N - 1];
    };
    
    int ans = 0;
    for (int d = 29; d >= 0; d--) {
        if (!check(ans | ((1 << d) - 1))) {
            ans |= 1 << d;
        }
    }
    
    std::cout << ans << "\n";
    
    return 0;
}

F

题意:1-n的排列,选一个开始,每次在R范围内下降高度大于D问最多能下降多少次


思路:高度从低到高遍历,seg维护高度-D时区间最大值,i是高度下标,每次找(i - R, i + R) 区间中的的最大值。

#include <bits/stdc++.h>

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

using u128 = unsigned __int128;
using i128 = __int128;
template<class Info>
struct SegmentTree {
    int n;
    std::vector<Info> info;
    SegmentTree() : n(0) {}
    SegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }
    template<class T>
    SegmentTree(std::vector<T> init_) {
        init(init_);
    }
    void init(int n_, Info v_ = Info()) {
        init(std::vector(n_, v_));
    }
    template<class T>
    void init(std::vector<T> init_) {
        n = init_.size();
        info.assign(4 << std::__lg(n), Info());
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init_[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {
            return -1;
        }
        if (l >= x && r <= y && !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F &&pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
    template<class F>
    int findLast(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {
            return -1;
        }
        if (l >= x && r <= y && !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findLast(2 * p + 1, m, r, x, y, pred);
        if (res == -1) {
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findLast(int l, int r, F &&pred) {
        return findLast(1, 0, n, l, r, pred);
    }
};

struct Max {
    int v = 0;
};

Max operator+(const Max &a, const Max &b) {
    return {std::max(a.v, b.v)};
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, D, R;
    std::cin >> N >> D >> R;
    
    std::vector<int> H(N), iH(N);
    for (int i = 0; i < N; i++) {
        std::cin >> H[i];
        H[i]--;
        iH[H[i]] = i;
    }
    
    SegmentTree<Max> seg(N);
    std::vector<int> dp(N);
    int ans = 0;
    for (int i = 0; i < N; i++) {
        int x = iH[i];
        if (i >= D) {
            seg.modify(iH[i - D], {dp[i - D]});
        }
        int res = 1 + seg.rangeQuery(std::max(0, x - R), std::min(N, x + 1 + R)).v;
        dp[i] = res;
        ans = std::max(ans, res);
    }
    std::cout << ans - 1 << "\n";
    
    return 0;
}

G

题意:

给你满足 $ \frac AB < \frac CD$ 的正整数 \(A,B,C,D\)

求满足以下条件的最小正整数 \(q\)

  • 存在一个正整数 \(p\) ,使得 $ \frac AB <\frac pq < \frac CD$ .

思路:

#include <bits/stdc++.h>

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

using u128 = unsigned __int128;
using i128 = __int128;

std::vector<i64> get(i64 a, i64 b) {
    std::vector<i64> v;
    while (a % b) {
        v.push_back(a / b);
        a %= b;
        std::swap(a, b);
    }
    v.push_back(a / b - 1);
    return v;
}

std::mt19937 rng;
void solve() {
    i64 A, B, C, D;
    std::cin >> A >> B >> C >> D;
    
    auto f = get(A, B);
    auto g = get(C, D);
    
    int l = std::max(f.size(), g.size()) + 2;
    f.resize(l);
    g.resize(l);
    if (f > g) {
        std::swap(f, g);
    }
    
    int i = 0;
    while (f[i] == g[i]) {
        i++;
    }
    
    if (*std::max_element(f.begin() + i + 1, f.end()) != 0) {
        f.resize(i + 1);
    } else if (f[i] + 1 < g[i]) {
        f[i]++;
        f.resize(i + 1);
    } else if (*std::max_element(g.begin() + i + 2, g.end()) != 0) {
        f[i]++;
        f[i + 1] = g[i + 1];
        f.resize(i + 2);
    } else {
        f[i]++;
        f[i + 1] = g[i + 1] + 1;
        f.resize(i + 2);
    }
    
    i64 p = 1, q = 1;
    for (int i = f.size() - 1; i >= 0; i--) {
        if (i % 2 == 1) {
            q += p * f[i];
        } else {
            p += q * f[i];
        }
    }
    
    std::cout << q << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int T;
    std::cin >> T;
    
    while (T--) {
        solve();
    }
    
    return 0;
}
posted @ 2025-11-10 16:59  filt  阅读(5)  评论(0)    收藏  举报