• CF1322B Present(思维 + 位运算 + 双指针 + 枚举)


    首先我们看到题目其实挺懵的。

    对于(a1 + a2) ^ (a1 + a3) ^ ... ^ (an-1 + an),感觉除了暴力一点办法都没有。

    其实我们可以看到。所有的括号外面其实都是异或符号。那么我们最后求的是一个异或的值。

    那么[0 - 1e7]异或的值必然不会超过2e7。于是我们可以考虑按位求每个数对的贡献。

    于是我们枚举 log2e7 约等于26

    之后我们要怎么求a + b对于k位的贡献呢?

    首先我们发现a + b是否对k位有贡献是取决于k-1位的数的。于是我们就可以对于每一位枚举先对数组进行一个模1 << (k+1)的操作

    于是我们继续观察两个[0, 1<<k+1 - 1]相加什么时候 k位会有1的贡献?

    于是我们就可以对取模后的数组进行sort,用双指针进行维护了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e6 + 10;
    
    int n;
    int a[maxn], b[maxn];
    
    bool cal(int L, int R) {
        ll res = 0;
        for (int i = n, l=1, r=1; i; i--) {
            while (l <= n && b[i]+b[l] < L) l++; ///找到第一个>=L的位置
            while (r <= n && b[i]+b[r] <= R) r++; ///找到第一个大于R的位置
            res += r-l - (i >= l && r > i); ///如果i在[L, R-1]那么要减去1,因为不能选自己
        }
        return (res/2) & 1; ///除以2是因为我们在计算数对的时候重复计算了两次 (i, j) (j, i)
    }
    
    int solve(int k) {
        int lmt = 1 << (k+1);
        for (int i = 1; i <= n; ++ i) {
            b[i] = a[i] % lmt;
        }
        sort(b+1, b+1+n);
        return cal(1<<k, (1<<(k+1))-1) ^ cal((1<<(k+1)) + (1<<k), (1<<(k+2))-2);
    }
    
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++ i) {
            scanf("%d", &a[i]);
        }
        int ans = 0;
        for (int i = 0; i < 30; ++ i) {
            ans |= (solve(i) << i);
        }
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    WAS日常维护中的重启时机——总结
    利用Shell生成Zabbix监控的数字报表
    Zabbix version upgrade (1.8.3 to 1.8.12)
    xeyes命令
    centos系统调节屏幕亮度
    centos7 安装kchmviewer 软件
    ftp使用FileZilla工具传输文件
    搭建vsftpd服务并实现本地用户访问
    centos中创建服务和关闭防火墙的基本命令
    阿里云vsftpd登录失败:530 Permission Denied.
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15128262.html
Copyright © 2020-2023  润新知