CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)

发布时间 2023-11-26 16:00:34作者: 洛绫璃

CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)

A - Jagged Swaps

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n;
        rep (i, 1, n) cin >> a[i];
        while (true) {
            bool f = 0;
            rep (i, 2, n - 1) if (a[i] > a[i - 1] && a[i] > a[i + 1]) {
                swap(a[i], a[i + 1]);
                f = 1;
            }
            if (!f) break;
        }
        bool f = 1;
        rep (i, 1, n) if (i != a[i]) {
            f = 0;
            break;
        }
        cout << (f ? "YES\n" : "NO\n");
    }
    return 0;
}

B - AB Flipping

正反各来一次

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> s + 1;
        int ans = 0;
        rep (i, 1, n) f[i] = 1;
        per (i, n - 1, 1) {
            if (s[i] == 'A' && s[i + 1] == 'B') {
                ++ans;
                swap(s[i], s[i + 1]);
                f[i] = 0;
            }
        }
        rep (i, 1, n - 1) {
            if (s[i] == 'A' && s[i + 1] == 'B' && f[i]) {
                ++ans;
                swap(s[i], s[i + 1]);
                f[i] = 0;
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

C - Matching Arrays

每次以贪心地增加/减少匹配项

const int N = 2e5 + 5;
 
int n, m, _, k, cas;
int a[N], b[N], c[N], d[N];
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m;
        rep (i, 1, n) cin >> a[i], c[i] = i;
        rep (i, 1, n) cin >> b[i];
        sort(c + 1, c + 1 + n, [&](int x, int y) { return a[x] < a[y]; });
        sort(b + 1, b + 1 + n);
        int cnt = 0;
        rep (i, 1, n) cnt += a[c[i]] > b[i];
        if (cnt < m) {
            set<PII> q;
            rep (i, 1, n) if (a[c[i]] <= b[i]) {
                if (!q.empty() && q.begin()->fi < a[c[i]]) {
                    int pp = q.begin()->se;
                    swap(b[i], b[pp]);
                    ++cnt;
                    if (cnt == m) break;
                    q.erase(q.begin());
                    q.emplace(b[pp], pp);
                } else {
                    q.emplace(b[i], i);
                }
            }
        } else if (cnt > m) {
            set<PII> q;
            rep (i, 1, n) if (a[c[i]] > b[i]) {
                if (!q.empty() && b[i] >= q.begin()->fi) {
                    int pp = q.begin()->se;
                    swap(b[i], b[pp]);
                    --cnt;
                    if (cnt == m) break;
                    q.erase(q.begin());
                }
                q.emplace(a[c[i]], i);
            }
        }
        if (cnt == m) {
            rep (i, 1, n) d[c[i]] = b[i];
            cout << "YES\n";
            rep (i, 1, n) cout << d[i] << ' ';
            cout << '\n';
        } else {
            cout << "NO\n";
        }
    }
    return 0;
}

D - Ones and Twos

考察奇偶性,考虑从头/尾丢弃 item 来使得剩余的子数组和等于所求

  1. 当头尾丢弃的 item 和是偶数时,必定有解,每次也偶数的从头/尾丢弃偶数即可(或者头尾一起各丢一个 1)

  2. 当头尾丢弃的 item 和是奇数是,先从数组头 or 尾贪心的选一个方向丢一个 1, 就可以转成情况 1 了(前提剩余 sum 可以凑出所求和)

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m;
        int s = 0;
        set<int> st;
        rep (i, 1, n) {
            cin >> a[i], s += a[i];
            if (a[i] == 1) st.emplace(i);
        }
        rep (i, 1, m) {
            int op; cin >> op;
            if (op == 2) {
                int x, y; cin >> x >> y;
                if (a[x] == 1) st.erase(x);
                s -= a[x]; a[x] = y;
                if (a[x] == 1) st.emplace(x);
                s += a[x];
            } else {
                int x; cin >> x;
                if (s < x) cout << "NO\n";
                else if (s == x) cout << "YES\n";
                else {
                    int z = s - x;
                    if (!(z & 1)) cout << "YES\n";
                    else if (!st.empty() && z >= (min(*st.begin() - 1, n - *st.rbegin()) << 1) + 1) cout << "YES\n";
                    else cout << "NO\n";
                } 
            }
        }
    }
    return 0;
}

E - Permutation Sorting

每个数字移动的距离不会超过 n, 为了方便计算,选择拆环,让 a[n + 1 ~ n * 2] = a[1 ~ n]

每个位置移动的绝对距离是 \(s_i\), 即 \((i + h_i − 1) % n =a_i - 1\)

然后就是考虑路径上哪些点 j 可以跳过,即 \(i < j < i + h_i and (i < a_j < i + h_i or i < a_j + n < i + h_i)\)

或者说对于点 i 的移动路径是 [l, r] (l = i, (r - 1) mod n + 1 = \(a_i\)), 他路径上可以跳过的点就是路径被 [l, r] 包含的路径

然后就是找个数据结构维护单点修改,区间查询路径上可以跳过的点数就好了

const int N = 1e6 + 5;
 
int n, m, _, cas;
int a[N], c[N << 1], ans[N];
 
void add(int x, int k) { for (; x <= n << 1; x += -x & x) c[x] += k; }
 
int ask(int x) { int ans = 0; for (; x; x -= x & -x) ans += c[x]; return ans; }
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n;
        memset(c, 0, sizeof(int) * n << 1);
        vector<PII> e;
        rep (i, 1, n) {
            cin >> a[i];
            if (i <= a[i]) {
                e.pb(i, a[i]);
                e.pb(i + n, a[i] + n);
            }
            else e.pb(i, a[i] + n);
        }
        sort(e.begin(), e.end(), greater<PII>());
        for (auto [l, r]: e) {
            if (l <= n) {
                ans[a[l]] = r - l - ask(r) + ask(l - 1);
            }
            add(r, 1);
        }
        rep (i, 1, n) cout << ans[i] << ' ';
        cout << '\n';
    }
    return 0;
}