• Kick Start 2019 Round D


    X or What?

    符号约定:

    • $xor$ 表示异或。
    • popcount($x$) 表示非负整数 $x$ 的二进制表示里数字 1 出现的次数。例如,$13 = 1101_2$,则 popcount(13) = 4。

    注意到,popcount($a xor b$) = popcount($a$) + popcount($b$) - 2 * number of positions both $a$ and $b$ are set。
    因此,popcount($a xor b$) 的奇偶性 = (popcount($a$) + popcount($b$)) 的奇偶性。

    区间 $[L, R]$ 的异或和的 popcount 为偶数 $iff$ $L - 1, R$ 这两个前缀的异或和的 popcount 同奇偶。

    分别考虑异或和的 popcount 为奇数的前缀、异或和的 popcount 为偶数的前缀。

    改变 $A_p$ 对答案的影响:
    若 $A_p$ 的 popcount 的奇偶性不变,则答案亦不变,否则 $p, p+1, dots, n - 1$ 这些前缀的异或和的 popcount 的奇偶性翻转。

    解法 1

    用线段树维护前缀的异或和的 popcount 的奇偶性。
    支持查询:

    • 异或和的 popcount 为偶数的前缀最后一次出现的位置。
    • 异或和的 popcount 为奇数的前缀第一次/最后一次出现的位置。
    bool bit_even(int x) {
        return (__builtin_popcount(x) & 1) == 0;
    }
    
    struct node {
      int n[2];
      int flipped;
      void flip() {
          swap(n[0], n[1]);
          flipped ^= 1;
      }
    };
    const int N = 100005;
    node seg[4 * N];
    
    int sum[N];
    void push_up(int i) {
        int l = i * 2, r = l + 1;
        for (int j = 0; j < 2; j++) {
            seg[i].n[j] = seg[l].n[j] + seg[r].n[j];
        }
    }
    
    void build (int i, int l, int r) {
        seg[i].flipped = 0;
        if (l == r) {
            seg[i].n[0] = bit_even(sum[l]);
            seg[i].n[1] = 1 - seg[i].n[0];
            return;
        }
        int mid = (l + r) / 2;
        build(i * 2, l, mid);
        build(i * 2 + 1, mid + 1, r);
        push_up(i);
    }
    
    void push_down(int i) {
        if (seg[i].flipped) {
            int l = i * 2, r = i * 2 + 1;
            seg[l].flip();
            seg[r].flip();
            seg[i].flipped = 0;
        }
    }
    
    int find_first(int v, int i, int l, int r) {
        if (seg[i].n[v] == 0) return r + 1;
        if (l == r) return l;
        push_down(i);
        int mid = (l + r) / 2;
        int res = find_first(v, i * 2, l, mid);
        if (res <= mid) {
            return res;
        }
        return find_first(v, i * 2 + 1, mid + 1, r);
    }
    
    int find_last(int v, int i, int l, int r) {
        if (seg[i].n[v] == 0) return l - 1;
        if (l == r) return l;
        push_down(i);
        int mid = (l + r) / 2;
        int res = find_last(v, i * 2 + 1, mid + 1, r);
        if (res > mid) {
            return res;
        }
        return find_last(v, i * 2, l, mid);
    }
    
    void flip(int i, int l, int r, int ql, int qr) {
        if (ql > r || qr < l) return;
        if (ql <= l && r <= qr) {
            seg[i].flip();
            return;
        }
        int mid = (l + r) / 2;
        push_down(i);
        flip(i * 2, l, mid, ql, qr);
        flip(i * 2 + 1, mid + 1, r, ql, qr);
        push_up(i);
    }
    
    
    int main() {
    #ifdef LOCAL
        ifstream in("main.in");
        cin.rdbuf(in.rdbuf());
    #endif
        int T; cin >> T;
        for (int cas = 1; cas <= T; ++cas) {
            cout << "Case #" << cas << ":";
            int n, q; cin >> n >> q;
            vector<int> a(n + 1);
            for (int i = 1; i <= n; i++) {
                cin >> a[i];
                sum[i] = sum[i - 1] ^ a[i];
            }
            build(1, 1, n);
            while (q--) {
                int p, v;
                cin >> p >> v;
                ++p;
                if (bit_even(v) != bit_even(a[p])) {
                    flip(1, 1, n, p, n);
                }
                a[p] = v;
                cout << " " << max(find_last(0, 1, 1, n), find_last(1, 1, 1, n) - find_first(1, 1, 1, n));
            }
            cout << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    jquery选择器[转]
    asp.net调用exe并传递参数然后关闭exe[转]
    JS操作JSON总结[转]
    Newtonsoft.Json序列化和反序列[转]
    jQuery EasyUI自定义DataGrid的Editor【转】
    【转】jquery easy UI datagrid新增一行,columns中editor下拉框之间的联动。
    jquery 表单序列化 转换json
    Jquery组合form元素为json格式,asp.net反序列化[转]
    什么是BOM头,及PHP解决办法
    PHP中去除字符串中的换行的方法
  • 原文地址:https://www.cnblogs.com/Patt/p/11260053.html
Copyright © 2020-2023  润新知