codeforces1323D Present

codeforces1323D/codeforces1322B Present
老年退役选手打打CF玩玩,发现自己智力降低过多,差点DIV2连D都没做出来
题意: 有n个整数,\(a_{1} a_{2} …… a_{n}\),求 \((a_1 +a_2) \oplus(a_1+a_3)\oplus……(a_1+a_n)\oplus(a_2 + a_3)\oplus……(a_2+a_n)\oplus……(a_n-1 + a_n)\)
其中 \((2 \leq n \leq 400,000) (1 \leq a_i \leq 10^7)\)

传送门

考虑异或的性质,令\(b_{i,j} = (a_i + a_j)\),对于每一个二进制位需要得到所有的\(b_{i,j}\) 的那一位上的异或和。

考虑\(a_i , a_j\)\(b_{i, j}\)的影响。
对于\(a_i , a_j\)的同一个二进制位,
不考虑进位当一个为0,一个为1时,\(b_{i, j}\)的对应位上得到一个1,
考虑进位,我们发现一个位是否有进位,跟右边的很多位都有关系,显然是无法记录状态进行DP的。
此时发现一个性质,对于两个二进制数的和,第i位是否进位,只与1~i-1位的和有关.
那么求进位就变得很简单了,我们只需要每次对所有\(a_i\)取前i位,然后计算i+1位发生了多少次进位就行(因为异或的性质,哪一对发生进位我们是不用关心的)
计算方式:取前i位,然后对新生成的数进行排序,维护一个从末尾单调向开头走的尾指针,求出发生进位的总次数

最后就把进位的贡献加在不考虑进位的贡献的结果上就行了

#include <bits/stdc++.h>
#include <tr1/unordered_map>
using namespace std;
inline void R (int &v) {
    static char ch;
    v = 0;
    bool p = 0;
    do {
        ch = getchar();
        if (ch == '-') p = 1;
    } while (!isdigit(ch));
    while (isdigit(ch)) {
        v = (v + (v << 2) << 1) + (ch ^ '0');
        ch = getchar();
    }
    if (p) v = -v;
}
inline void R (long long &v) {
    static char ch;
    v = 0;
    bool p = 0;
    do {
        ch = getchar();
        if (ch == '-') p = 1;
    } while (!isdigit(ch));
    while (isdigit(ch)) {
        v = (v + (v << 2) << 1) + (ch ^ '0');
        ch = getchar();
    }
    if (p) v = -v;
}
int n; 
int a[400005];
int t[32];
int c;
inline bool cmp(const int a, const int b) {
    return (a & t[c]) < (b & t[c]);
}
int one[32], zero[32];
long long newone[32];
inline void count(int x) {
    int now = 1; 
    for(int i = 0; i <= 25; ++i) {
        if(now & x) {
            one[i]++;
        } else {
            zero[i]++;
        }
        now <<= 1;
    }
}
int jinwei[32];
int main() {
    R(n);
    for(int i = 1; i <= n; ++i) {
        R(a[i]);
    }
    for(int i = 1; i <= n; ++i) {
        count(a[i]);
    }
    t[0] = 1;
    for(int i = 1; i <= 31; ++i) t[i] = (t[i - 1] << 1) + 1;
    for(int i = 0; i <= 26; ++i) {
        c = i;
        sort(a + 1, a + n + 1, cmp);
        int tail = n + 1;
        int now = 0;
        for(register int j = 1; j <= n; ++j) {
            if(j >= tail) {
                jinwei[i + 1] += n - j;
                continue;
            } else {
                while(((a[j] & t[c]) + (a[tail - 1] &t[c])) & (1 << i + 1) && (tail - 1 > j)) {
                    --tail;
                    ++now;
                }
                jinwei[i + 1] += now;
            }
            
        }
    }
    for(int i = 0; i <= 27; ++i) {
        newone[i] += (long long)one[i] * zero[i] + jinwei[i]; 
    }
    int now = 1;
    int daan = 0;
    for(int i = 0; i <= 25; ++i) {
        
        if(newone[i] % 2) {
            daan += now;
        }
        now <<= 1;
    }
    cout << daan << '\n';
    return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/thhyj/p/12441541.html