[Codeforces 1323D] Present

https://codeforces.com/contest/1323/problem/D

题意:
\(a\) 序列中所有无序对 \(x, y\) \((x \lt y)\) 和(即 \(a_x + a_y\) )的异或和。

思路:

位运算考虑拆位思考。设当前二进制位为第 \(k\) 位,如果第 \(k\) 位有贡献当且仅当有奇数个 \(1\) 。考虑如何快速计算 \(1\) 的数量。两数做加法后,第 \(k\) 位仅受到 前 \(k\) 位影响。所以我们从高到低,每次仅保留 \(0\) ~ \(k\) 位,发现对于给定的 \(a_x\)\(a_y\),需要满足 \(a_x + a_y\) \(\in\) \([2^k, 2^{k + 1} - 1]\) \(\bigvee\) \([2^{k + 1} + 2^k, 2^{k + 2} - 1]\) 。我们可以每次处理完 \(a\) 后对其排序,确定 \(x\) 后找 \(y\) 的数量,得到一个时间复杂度 \(O(nlog^2n)\) 的可通过的程序。

进一步考虑性质。因为 \(a\) 有序了,所以如果有序取 \(x\) ,那么 \(y\) 的区间范围也是单调的。而对 \(a\) 排序可以将上一次的 \(a\) 分成两个有序序列,做一个归并排序。由此我们得到了时间复杂度 \(O(nlogn)\) 的优秀程序。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    sort(a.begin(), a.end());
    int ans = 0;
    for (int k = 25; k >= 0; --k) {
        vector<int> A, B;
        for (int i = n - 1; i >= 0; --i) {
            if (a[i] >> (k + 1) & 1) {
                A.emplace_back(a[i]);
            }
            else B.emplace_back(a[i]);
        }
        a.clear();
        for (auto &u : A) {
            u ^= (1 << (k + 1));
        }
        while (!A.empty() || !B.empty()) {
            if (A.empty()) {
                a.emplace_back(B.back());
                B.pop_back();
            } else if (B.empty()) {
                a.emplace_back(A.back());
                A.pop_back();
            } else if (A.back() < B.back()) {
                a.emplace_back(A.back());
                A.pop_back();
            } else {
                a.emplace_back(B.back());
                B.pop_back();
            }
        }
        int num = 0;
        int head1 = n, head2 = n, rear1 = n, rear2 = n;
        for (int i = 0; i < n; ++i) {
            while (head1 > i && a[head1 - 1] >= (1 << k) - a[i]) head1--;
            while (rear1 > i && a[rear1 - 1] > (1 << (k + 1)) - 1 - a[i]) rear1--;
            if (head1 <= i) head1 = i + 1;
            if (rear1 > i) num += rear1 - head1;

            while (head2 > i && a[head2 - 1] >= (1 << (k + 1)) + (1 << k) - a[i]) head2--;
            while (rear2 > i && a[rear2 - 1] > (1 << (k + 2)) - 1 - a[i]) rear2--;
            if (head2 <= i) head2 = i + 1;
            if (rear2 > i) num += rear2 - head2;
        }
        if (num & 1) ans += 1 << k;
    }
    cout << ans << '\n';
}

int main() {
#ifndef stff577
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    cout << fixed << setprecision(20);
#endif
    int t = 1;
    while (t--) solve();
    return 0;
}
posted @ 2022-08-02 10:27  stff577  阅读(21)  评论(0编辑  收藏  举报