zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Java 反射机制
    Hibernate学习
    js学习
    如何在jsp中引入bootstrap
    bootstrap学习一
    第二章、初级篇
    定风波
    Java反射机制
    数据库的优化方法
    MySQL常用的查询语句回顾
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15128262.html
Copyright © 2011-2022 走看看