zoukankan      html  css  js  c++  java
  • Codeforces Round #626 Div2 D. Present(位掩码,二分)

    题目链接:https://codeforces.com/contest/1323/problem/D

    题意:给了大小为4e5的数组a,其中1<=ai<=1e7。求所有点对和的异或和,即:


    思路:

    • 按位来考虑,因为两个元素的和<=2e7,而2e7小于225,因此结果最多是25位。我们考虑答案中每一位ans[k]的值(0<=k<=24)。
    • 显然,ai中仅有0~k位会对第k位有影响,因此对数组a全部对2k+1取模,得到数组b,对b按升序排序。
    • 这样,0<=bi<=2k+1-1,两个bi的和<=2k+2-2。要使得和的第k位为1,和的范围应该为[ 2k , 2k+1-1 ] (区间1)或者 [ 2k+2k+1 , 2k+2-2] (区间2)。
    • 枚举bi,对两个区间可分别得到另一个和bi相加的元素bj的范围大小,利用二分查找bj的区间,从而得到bj的个数num。枚举完之后num%2=1的话,答案中的第k位便是1。
    • 另外,如果bi<=2k,那么bi和另一个元素的和只可能在区间1内,否则既可以在区间1,也可以在区间2。

    AC code:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int maxn=4e5+5;
    typedef long long LL;
    int n,a[maxn],b[maxn],p[30],ans,MOD;
    
    void init(){
        p[0]=1;
        for(int i=1;i<=26;++i)
            p[i]=p[i-1]<<1;
    }
    
    int bs1(int ll,int rr,int v){
        int l=ll,r=rr,mid;
        while(l<=r){
            mid=(l+r)>>1;
            if(b[mid]>=v) r=mid-1;
            else l=mid+1;
        }
        return l;
    }
    
    int bs2(int ll,int rr,int v){
        int l=ll,r=rr,mid;
        while(l<=r){
            mid=(l+r)>>1;
            if(b[mid]<=v) l=mid+1;
            else r=mid-1;
        }
        return r;
    }
    
    int main(){
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        for(int k=0;k<=24;++k){
            LL num=0;
            MOD=p[k+1];
            for(int i=1;i<=n;++i)
                b[i]=a[i]%MOD;
            sort(b+1,b+n+1);
            for(int i=1;i<n;++i){
                int le=max(p[k]-b[i],0),ri=p[k+1]-1-b[i];
                int l=bs1(i+1,n,le);
                int r=bs2(i+1,n,ri);
                num+=(LL)(r-l+1);
                if(b[i]<=p[k]) continue;
                le=p[k+1]+p[k]-b[i],ri=p[k+2]-2-b[i];
                l=bs1(i+1,n,le);
                r=bs2(i+1,n,ri);
                num+=(LL)(r-l+1);
            }
            if((int)(num%2)==1) ans+=p[k];
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    linux下使用c99链接libuv遇到的问题
    linux连接lua遇到的问题
    uv_timer_t的释放问题
    libuv的源码分析(1)
    [转]关于截取字符串substr和substring两者的区别
    输入框获取焦点后placeholder文字消失、修改placeholder的样式
    发送验证码功能
    针对移动浏览器判断不同的内核的方法
    preventDefault()对象
    [转]JQ中$(window).load和$(document).ready区别与执行顺序
  • 原文地址:https://www.cnblogs.com/FrankChen831X/p/12442160.html
Copyright © 2011-2022 走看看