Hello 2025

A. MEX Table

题目大意

给你一个 \(n*m\) 的矩阵,用 从0开始的 \(n*m\) 的排列去填充,问能构造出的最大mex列或者行是多大

解题思路

0开始的连续数字只能填充在一行或者一列,二者取大即可

代码实现

#include <bits/stdc++.h>

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int n, m;
        std::cin >> n >> m;

        std::cout << std::max(n, m) + 1 << "\n";
    }
}

B. Gorilla and the Exam

题目大意

给你一个数组,每次可以选择一个区间删除所有和最小值相等的值,能修改k个数字,问至少要删多少次才能删光数组

解题思路

简单观察就能发现,删除整个数组始终都是最优的,题目就转换为有多少种不一样的数字,因此只需要把数量少的数字给数量多的数字让最后不同种类的数字数量尽可能少就行

代码实现

#include <bits/stdc++.h>

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int n, k;
        std::cin >> n >> k;

        std::map<int, int> mp;
        std::vector<int> a(n);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            mp[a[i]]++;
        }

        std::vector<std::array<int, 2>> v;
        for (auto [x, y] : mp) {
            v.push_back({x, y});
        }

        std::sort(v.begin(), v.end(), [&](std::array<int, 2> a, std::array<int, 2> b) { return a[1] < b[1]; });

        int m = v.size(), f = 1;
        for (int i = 0; i < m - 1; i++) {
            k -= v[i][1];
            if (k < 0) {
                std::cout << m - i << "\n";
                f = 0;
                break;
            }
        }

        if (f) {
            std::cout << 1 << "\n";
        }
    }
}

C. Trip to the Olympiad

题目大意

给你一个lr区间,找出3个数字使他们两两异或的和最大

解题思路

找到lr在二进制下最高不同的位使得a在这位为1后面全是0,b在这位为0后面全是1,c前面部分相同后面任意,这样就能使得lr第一个不同位及其之后的每一位都为1

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int l, r;
        std::cin >> l >> r;
        int a = l | ((1 << (std::__lg(l ^ r))) - 1), b = a + 1, c = (a == l ? r : l);
        std::cout << a << " " << b << " " << c << "\n";
    }
}

D. Gifts Order

题目大意

给你一个数组,求区间极差减去区间长度的最大值,会有多次修改,每次回答修改前后的最大值

解题思路

首先想到的是这两个最值一定是在区间两侧的,否则长度增加极差不变会让这个最大值变小,而根据两个极值的位置可以分为两种情况:

  • 最大值在左侧,则答案是 \(a_l - a_r - (r - l) = (a_l + l) - (a_r + r)\)
  • 最小值在左侧,则答案是 \(a_r - a_l - (r - l) = (a_r - r) - (a_l - l)\)

所以只需要线段树维护 \(a_i + i\)\(a_i - i\) 的最大最小值以及当前节点的答案即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const i64 INF = 4e18;

class SegmentTree {
   public:
    int n;
    std::vector<i64> maxl, maxr, minl, minr, ans;

    SegmentTree(int n) : n(n), maxl(4 * n, -INF), maxr(4 * n, -INF), minl(4 * n, INF), minr(4 * n, INF), ans(4 * n) {
    }

    void update(int node, int l, int r, int pos, i64 val) {
        if (l == r) {
            maxl[node] = val + pos;
            maxr[node] = val - pos;
            minl[node] = val - pos;
            minr[node] = val + pos;
            ans[node] = 0;
            return;
        }
        int mid = (l + r) / 2;
        if (pos <= mid) {
            update(2 * node, l, mid, pos, val);
        } else {
            update(2 * node + 1, mid + 1, r, pos, val);
        }
        pushup(node);
    }

    void pushup(int pos) {
        maxl[pos] = std::max(maxl[2 * pos], maxl[2 * pos + 1]);
        maxr[pos] = std::max(maxr[2 * pos], maxr[2 * pos + 1]);
        minl[pos] = std::min(minl[2 * pos], minl[2 * pos + 1]);
        minr[pos] = std::min(minr[2 * pos], minr[2 * pos + 1]);
        ans[pos] = std::max({ans[2 * pos], ans[2 * pos + 1], maxl[2 * pos] - minr[2 * pos + 1], maxr[2 * pos + 1] - minl[2 * pos]});
    }

    i64 rangeQuery(int node, int l, int r, int st, int ed) {
        if (r < st || l > ed) {
            return 0;
        }
        if (l >= st && r <= ed) {
            return ans[node];
        }
        int mid = (l + r) / 2;
        return std::max(rangeQuery(2 * node, l, mid, st, ed), rangeQuery(2 * node + 1, mid + 1, r, st, ed));
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, q;
        std::cin >> n >> q;

        SegmentTree seg(n);
        for (int i = 1; i <= n; i++) {
            int a;
            std::cin >> a;
            seg.update(1, 1, n, i, a);
        }

        std::cout << seg.rangeQuery(1, 1, n, 1, n) << "\n";

        while (q--) {
            int p, x;
            std::cin >> p >> x;
            seg.update(1, 1, n, p, x);
            std::cout << seg.rangeQuery(1, 1, n, 1, n) << "\n";
        }
    }
}
posted @ 2025-02-21 23:40  udiandianis  阅读(20)  评论(0)    收藏  举报