AtCoder Beginner Contest 343

kdlyh / 2024-03-03 / 原文

基本情况

前四题秒了,但是都有不够优雅的地方

F知道是线段树,但是写不出来,极其绝望

C - 343

C - 343 (atcoder.jp)

更简洁的回文判断

MyCode

bool check_p(i64 x) {
    std::string s(std::to_string(x));
    int n = sz(s);
    for (int i = 0; i < n / 2; i++) {
        if (s[i] != s[n - i - 1]) return false;
    }
    return true;
}

signed main(){

    constexpr int N(1E6 + 10);

    std::cin >> n;
    
    i64 ans(1);

    for (i64 i = 0; i < N; i++) {
        i64 num = i * i * i;
        if (num > n) {std::cout << ans << '\n'; return 0;}
        if (check_p(num)) ans = num;
    }

    std::cout << ans << '\n';

    return 0;
}

STD

int main() {

    i64 N;
    std::cin >> N;
    
    i64 ans = 0;
    for (i64 a = 1; a * a * a <= N; a++) {
        std::string s = std::to_string(a * a * a);
        if (s == std::string(s.rbegin(), s.rend())) {//更简洁的回文判断
            ans = a * a * a;
        }
    }
    std::cout << ans << "\n";
    
    return 0;
}

D - Diversity of Scores

D - Diversity of Scores (atcoder.jp)

不知道map可以erase导致的

MyCode

signed main(){
    int N, T;
    std::cin >> N >> T;
    std::vector<i64> a(N);
    std::set<i64> S(all(a));
    std::map<i64, int> cnt;
    cnt[0] = N;
    for (int _ = 1; _ <= T; _++) {
        int idx; i64 add;
        std::cin >> idx >> add;
        idx--;
        if (cnt.count(a[idx])) {
            cnt[a[idx]]--;
            if (cnt[a[idx]] == 0) {
                S.erase(a[idx]);
            }
        }
        a[idx] += add;
        cnt[a[idx]]++;
        S.insert(a[idx]);
        std::cout << sz(S) << '\n';
    }
    return 0;
}

STD

signed main(){
    int N, T;
    std::cin >> N >> T;
    std::vector<i64> a(N);
    std::map<i64, int> cnt;
    cnt[0] = N;
    for (int _ = 1; _ <= T; _++) {
        int idx; i64 add;
        std::cin >> idx >> add;
        idx--;
        if (--cnt[a[idx]] == 0) cnt.erase(a[idx]);//直接用map执行删除操作就行
        a[idx] += add;
        cnt[a[idx]]++;
        std::cout << sz(cnt) << '\n';
    }
    return 0;
}

F - Second Largest Query

F - Second Largest Query (atcoder.jp)

线段树掌握不到位

这里只需要维护次大值,并不需要主席树

而且也不需要通过map等暴力统计次大值数量,可以优雅地直接用线段树在合并时维护

#include <bits/stdc++.h>

using i64 = long long;
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 || !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 || !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 Info {
    int max_1 = -1;
    int cnt_1 = 0;
    int max_2 = -2;
    int cnt_2 = 0;
};

Info operator+(Info a, Info b) {//区间合并维护次大值和次大值个数
    
    if (a.max_1 == b.max_1) {//如果两个区间最大值相等
        if (a.max_2 < b.max_2) {
            std::swap(a, b);
        }   
        a.cnt_1 += b.cnt_1;
        if (a.max_2 == b.max_2) {
            a.cnt_2 += b.cnt_2;
        }
    }
    else {//如果两个区间最大值不等
        if (a.max_1 < b.max_1) {//先把情况变成a最大值最大
            std::swap(a, b);
        }
        if (b.max_1 > a.max_2) {
            //如果b的最大值比a的次大值大(此时a的最大值肯定是最大的,所以b的最大值就是次大值)
            //此时并不用考虑b的次大值,因为该结构要求了次大值严格小于最大值,既然b的最大值已经小于a了,那么b的次大值只能更小
            a.max_2 = b.max_1;//维护次大值
            a.cnt_2 = b.cnt_1;//显然次大值改变了,所以个数改成b的最大值的个数
        }
        else if (b.max_1 == a.max_2) {//两个都是次大值,就相加
            a.cnt_2 += b.cnt_1;
        }
    }
    return a; 
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N, Q;
    std::cin >> N >> Q;
    
    std::vector<int> A(N);
    for (int i = 0; i < N; i++) {
        std::cin >> A[i];
    }
    
    SegmentTree<Info> seg(N);

    for (int i = 0; i < N; i++) {
        seg.modify(i, {A[i], 1, -1, 0});//单点修改,最大值等于自己,个数为1.没有次大值,所以设成{0, 1}
    }

    while(Q--) {
        int o;
        std::cin >> o;

        if (o == 1) {
            int p, x;
            std::cin >> p >> x;
            p--;
            seg.modify(p, {x, 1, -1, 0});
        }
        else {
            int l, r;
            std::cin >> l >> r;
            l--;//左闭右开
            std::cout << seg.rangeQuery(l, r).cnt_2 << '\n';
        }
    }

    return 0;
}