• 2021牛客多校第三场 I. Kuriyama Mirai and Exclusive Or (位运算+差分)


    题意就是给你一个长度为n的数组,之后有两种操作,第一种是[L, R]都异或上x,第二种是[L, R]异或上x, x+1, x+2, x+3...

    对于第一个操作我们非常容易就能操作,即异或差分数组。

    但是对于第二个操作我们就比较头疼了,我们要怎么把 + 符号去掉变成 ^ 呢。 (因为异或是不满足分配律的所以我们需要想办法把这个+号去掉。

    考虑到如果我们将 x 分为 k块(k为x的二进制1的个数)。

    为什么这样分呢,因为我们发现假设 lowbit(x) = k,  那么a1 ^ (x + 1) 就会等价于 a1 ^ x ^ 1因为在lowbit前面的都是0,0异或任何数字就是加上这个数字。

    并且我们设置一个标记数组flag[i][j],表示从i位置开始,需要往长度为2的 j 次的块上,异或上0, 1, 2..., 2的 j 次-1

    所以操作2,其实就是往块的两边^ 2的k次,之后再给块的开头打上标记。

    之后考虑如何将标记下传到原数组。这里其实像是一个倍增的思想,也很像线段树里的push_down,就是说如果flag[ i ] [ j ]有标记的话,就意味着,i  -  i+2的(j-1)次, i+2的(j-1)次 - i + 2的 j 次上都会需要有这个操作。

    于是我们就可以将flag[ i ] [ j ]下放到, flag[ i ] [ j-1]和 flag[ i + 2的j-1次] [ j-1 ],同时对差分数组的 i + 2的j-1次与i + 2的j次的位置异或上 2的j-1次。就相当于是,往后半个块上异或上 2 的 j -1次。

    参考博客:https://blog.csdn.net/weixin_45775438/article/details/119654815?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-8.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-8.no_search_link

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int inf = 0x3f3f3f3f; ///1061109567
    const int maxn = 6e5 + 10;
    
    int chafen[maxn];
    int flag[maxn][21];
    int a[maxn], pw[21];
    
    int main() {
        int n, q; scanf("%d%d", &n, &q);
        for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
        pw[0] = 1;
        for (int i = 1; i <= 20; ++ i) pw[i] = pw[i-1]*2;
    
        while (q--) {
            int op; scanf("%d", &op);
            int l, r, x; scanf("%d%d%d", &l, &r, &x);
            if (op == 0) {
                chafen[l] ^= x;
                chafen[r+1] ^= x;
            }
            else {
                for (int j = 0; j <= 20; ++ j) {
                    if (((x >> j) & 1) && (l + pw[j] - 1) <= r) {
                        chafen[l] ^= x;
                        chafen[l+pw[j]] ^= x;
                        flag[l][j] ^= 1;
    
                        x += pw[j];
                        l += pw[j];
                    }
                }
                for (int j = 20; j >= 0; j --) {
                    if (l + pw[j]-1 <= r) {
                        chafen[l] ^= x;
                        chafen[l+pw[j]] ^= x;
    
                        flag[l][j] ^= 1;
    
                        x += pw[j];
                        l += pw[j];
                    }
                }
            }
        }
        for (int j = 20; j >= 1; j --) {
            for (int i = 1; i <= n; ++ i) {
                if (flag[i][j]) {
                    flag[i][j-1] ^= 1;
                    flag[i+pw[j-1]][j-1] ^= 1;
    
                    chafen[i+pw[j-1]] ^= pw[j-1];
                    chafen[i+pw[j]] ^= pw[j-1];
                }
            }
        }
        for (int i = 1; i <= n; ++ i) {
            chafen[i] ^= chafen[i-1];
            printf("%d%c", a[i] ^ chafen[i], " 
    "[i==n]);
        }
        return 0;
    }
  • 相关阅读:
    Vim 在 windows 环境下的初步配置
    空间向量在任意平面的投影公式推导 (矩阵方法)
    jquery中获取元素的几种方式小结
    开源框架
    将插入的新行放入dataGridView的第一行
    go-mod 入门
    docker 常用启动命令
    golang str 首字母大写
    遇到过的几个难搞的问题
    jwt、session、oauth 异同
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15401431.html
Copyright © 2020-2023  润新知