Codeforces Round #626 (Div. 2) D. Present(位运算)

题意:

求n个数中两两和的异或。

思路:

逐位考虑,第k位只需考虑0~k-1位,可通过&(2k+1-1)得到一组新数。

将新数排序,当两数和在[2k,2k+1)和[2k+1+2k,2k+2)之间时该位为1,又因为两数的最大和为2*(2k+1-1)=2k+2-2,

即当两数和在[2k,2k+1)和[2k+1+2k,2k+2-2]之间时该位为1。

对于每个数,找到和

    大于等于2k

    小于2k+1

    大于等于2k+1+2k

的三个临界点(因为两数之和一定小于等于2k+2-2,所以第四个临界点可以忽略),

位于它们间的数与该数的和在第k位即为1,统计1的个数,该位异或偶数次后为0,异或奇数次后为1。

Tips:

调试了半天发现少加了一对括号,以后还是不要猜优先级了。

#include <bits/stdc++.h>
using namespace std;

const int MAX_N=1e6;

int n,ans;
int a[MAX_N],b[MAX_N];

int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];

    for(int k=0;k<25;k++){
        for(int i=0;i<n;i++)
            b[i]=a[i]&((1<<(k+1))-1);
        sort(b,b+n);

        int d=1<<k;
        int cnt=0;

        for(int i=n-1,x=0,y=0,z=0;i>=0;i--){
            while(x<n&&b[x]+b[i]<d) x++;
            while(y<n&&b[y]+b[i]<2*d) y++;
            while(z<n&&b[z]+b[i]<3*d) z++;

            cnt+=max(0,min(i,y)-x);
            cnt+=max(0,i-z);
        }

        if(cnt&1)
            ans|=1<<k;
    }

    cout<<ans<<endl;

    return 0;
}

 

posted @ 2020-03-11 18:08  Kanoon  阅读(175)  评论(0编辑  收藏  举报