The 2024 ICPC Asia East Continent Online Contest (I)

A. World Cup

这道题目难点主要是读懂题意,然后按照题意手玩一下就出来了。

按照题目手玩一下样例就可以找到规律,在采取最优分组策略的情况下,能够影响的结果的就是比自己分数的低的人的个数。

当进入 32 强后,如果有2个人比你的分数低,你就晋级。

当进入 16 强后,有两种情况,在你自己的组排第一,要有3 个人比你低,你要赢得另一组的第二,还有3个人比你低。另一种情况是在你的组排第二,你要比 2 个人要高,同时你要比另一组的第一高,因此还有4 个人比你低。所以晋级的条件是有 6 个人比你分数低。

进入 8 强后,你本身比 6 个人分数高,你要赢另一个人,同时他也比 6 个人高,因此晋级条件是比 13 个人分数高。

进入 4 强后,推理同 8 强你要比 27 个人高。

进入决赛后,很简单比所有人都高,也就是 31 个人。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;

void solve() {
    int n = 32;
    vi a(n);
    for (auto &i: a) cin >> i;
    int cnt = 0;
    for (int i = 1; i < n; i++)
        cnt += a[0] > a[i];
    if (cnt < 2) cout << "32\n";
    else if (cnt < 6) cout << "16\n";
    else if (cnt < 13) cout << "8\n";
    else if (cnt < 27) cout << "4\n";
    else if (cnt < 31) cout << "2\n";
    else cout << "1\n";
}

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

F. Make Max

可以想到的是,一定是吧最小值一点点变大,这样是最优的。

那么我们就应该假设我们找到了最小值,并且最小值是连续的一段\([l,r]\)我们就应该找到这一段的左侧和右侧,选取较小值吧这一段变大,产生的贡献就是\(r-1+1\)

这里我用了类似珂朵莉树的方法,分别按照顺序维护段和大小维护段,然后暴力的模拟就好了,以为每次操作可以使得段的数量至少减1,复杂度\(O(N\log N)\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;

struct seg1 {
    int l, r, v;

    seg1(int l, int r = 0, int v = 0) : l(l), r(r), v(v) {}

    bool operator<(const seg1 &b) const {
        return l < b.l;
    }
};

struct seg2 {
    int l, r, v;

    seg2(int l, int r = 0, int v = 0) : l(l), r(r), v(v) {}

    bool operator<(const seg2 &b) const {
        if (v != b.v) return v < b.v;
        return l < b.l;
    }
};

void solve() {
    int n;
    cin >> n;
    set<seg1> cnt1;
    set<seg2> cnt2;
    vi a(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int l = 1, r; l <= n;) {
        r = l;
        while (r + 1 <= n and a[r + 1] == a[l]) r++;
        cnt1.emplace(l, r, a[l]);
        cnt2.emplace(l, r, a[l]);
        l = r + 1;
    }
    int res = 0;
    while (cnt2.size() > 1) {
        auto [l, r, v] = *cnt2.begin();
        cnt2.erase(cnt2.begin());
        cnt1.erase(cnt1.lower_bound(seg1(l, r, v)));
        res += r - l + 1;
        auto it = cnt1.lower_bound(seg1(l));
        if (it == cnt1.end()) {
            it = prev(it);
            auto [nl, nr, nv] = *it;
            cnt1.erase(it);
            cnt2.erase(cnt2.lower_bound(seg2(nl, nr, nv)));
            nl = min(nl, l), nr = max(nr, r), nv = max(nv, v);
            cnt1.emplace(nl, nr, nv);
            cnt2.emplace(nl, nr, nv);
        } else if (it == cnt1.begin()) {
            auto [nl, nr, nv] = *it;
            cnt1.erase(it);
            cnt2.erase(cnt2.lower_bound(seg2(nl, nr, nv)));
            nl = min(nl, l), nr = max(nr, r), nv = max(nv, v);
            cnt1.emplace(nl, nr, nv);
            cnt2.emplace(nl, nr, nv);
        } else {
            auto pit = prev(it);
            if (pit->v == it->v) {
                auto [nl, nr, nv] = *it;
                cnt1.erase(it);
                cnt2.erase(cnt2.lower_bound(seg2(nl, nr, nv)));
                auto [pl, pr, pv] = *pit;
                cnt1.erase(pit);
                cnt2.erase(cnt2.lower_bound(seg2(pl, pr, pv)));
                nl = min(nl, pl), nr = max(nr, pr);

                nl = min(nl, l), nr = max(nr, r), nv = max(nv, v);
                cnt1.emplace(nl, nr, nv);
                cnt2.emplace(nl, nr, nv);
            } else {
                if (pit->v < it->v) it = pit;
                auto [nl, nr, nv] = *it;
                cnt1.erase(it);
                cnt2.erase(cnt2.lower_bound(seg2(nl, nr, nv)));
                nl = min(nl, l), nr = max(nr, r), nv = max(nv, v);
                cnt1.emplace(nl, nr, nv);
                cnt2.emplace(nl, nr, nv);
            }
        }
    }
    cout << res << "\n";
}

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

G. The Median of the Median of the Median

先用对顶堆求出\(b\)数组。

然后我们可以二分答案,二分枚举\(x\),然后把\(b\)数组内小于等于\(x\)的比标记为\(1\)。然后用前缀和维护一下,当我需要计算\(c\)数组的时候就可以\(O(1)\)的计算出区间内总数和小于等于\(x\)的数量,因此可以判断出当前的\(c\)是否大于等于\(x\)。然后我们在统计\(c\)种大于等于\(x\)的个数,如果超过了一半,说明中位数大于等于\(x\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;

struct Median {
    int m, n;
    priority_queue<int> l;
    priority_queue<int, vi, greater<>> r;

    Median() {
        n = m = 0;
    }

    void insert(int x) {
        n++;
        if (n == 1) {
            m = x;
            return;
        }
        if (x <= m) l.push(x);
        else r.push(x);
        int t = (n + 1) / 2 - 1;
        while (l.size() > t) {
            r.push(m), m = l.top(), l.pop();
        }
        while (l.size() < t) {
            l.push(m), m = r.top(), r.pop();
        }
    }

};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];
    vector b(n + 1, vi(n + 1));
    for (int i = 1; i <= n; i++) {
        Median median;
        for (int j = i; j <= n; j++) {
            median.insert(a[j]);
            b[i][j] = median.m;
        }
    }
    auto t = [](int k) {
        k = (1 + k) * k / 2;
        return (k + 1) / 2;
    };
    auto check = [&](int x) -> bool {
        vector c(n + 2, vi(n + 2));
        for (int j = 1; j <= n; j++)
            for (int i = j; i >= 1; i--)
                c[i][j] = (b[i][j] <= x) + c[i + 1][j];

        int cnt = 0;
        for (int l = 1; l <= n; l++)
            for (int r = l, sum = 0; r <= n; r++) {
                sum += c[l][r];
                if (sum >= t(r - l + 1))
                    cnt++;
            }
        return cnt >= t(n);
    };
    int l = 1, r = 1e9, res = -1;
    while (l <= r) {
        int mid = (l + r) / 2;
        if (check(mid)) res = mid, r = mid - 1;
        else l = mid + 1;
    }
    cout << res;
    return 0;
}

M. Find the Easiest Problem

map<string,set<string>>统计一下每道题目的通过人数就好了。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

void solve() {
    int n;
    cin >> n;
    map<string, set<string>> cnt;
    for (string team, problem, result; n; n--) {
        cin >> team >> problem >> result;
        if (result != "accepted") continue;
        cnt[problem].insert(team);
    }
    string res;
    int val = 0;
    for (auto [i, v]: cnt) {
        if (v.size() > val) val = v.size(), res = i;
    }
    cout << res << "\n";
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}
posted @ 2024-09-17 21:31  PHarr  阅读(133)  评论(0编辑  收藏  举报