【杂题】[AtCoder Regular Contest 092 D] Two Sequences

题意:

给出两个长度为N的序列A,B,求:

(A1+B1)(A1+B2)(A1+B3)(A2+B1)(A2+B2)(A2+B3)(An+Bn) ( A 1 + B 1 ) ⊕ ( A 1 + B 2 ) ⊕ ( A 1 + B 3 ) ⊕ … … ⊕ ( A 2 + B 1 ) ⊕ ( A 2 + B 2 ) ⊕ ( A 2 + B 3 ) ⊕ … … ⊕ ( A n + B n )


分析:

首先,主要的方法还是构造,如果我们要求答案的二进制下第 k k 位,那么很显然的一点是,A与B中所有高于第k位的部分一定对这一位的答案无任何影响,所以我们将所有数全部模 2k+1 2 k + 1
再来观察所有数的和中,第 k k 位为1的数的特点:设该数为x
则必然满足 2kx<2×2k3×2kx<4×2k 2 k ≤ x < 2 × 2 k 或 3 × 2 k ≤ x < 4 × 2 k
证明很显然,因为每个数都严格小与 2k+1 2 k + 1 ,所以相加之和必然小于 2×2k+1 2 × 2 k + 1 ,在这类数中,若二进制下第 k k 位为1,则其必然大于等于2k,但大于等于 2k 2 k 中也有一部分数的第k位为0的。即第 k+1 k + 1 位为1,第 k k 位为0。这种数必然在[2k+1,2k+1+2k)之间

所以,我们只需要将所有数取模后,将b数列排序,a数列依次取出一个数 (ai) ( a i ) ,求出在另一个数列中值在 [2kai2×2kai)[3×2kai,4×2kai) [ 2 k − a i , 2 × 2 k − a i ) 与 [ 3 × 2 k − a i , 4 × 2 k − a i ) 内的数的个数即可。具体方法可以用lower_bound

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 200010
using namespace std;
int a[MAXN],b[MAXN],a1[MAXN],b1[MAXN];
int ans,n,sum;
int main(){
    SF("%d",&n);
    for(int i=0;i<n;i++)
        SF("%d",&a[i]);
    for(int i=0;i<n;i++)
        SF("%d",&b[i]);
    for(int i=0;i<29;i++){
        for(int j=0;j<n;j++){
            a1[j]=a[j]%(1<<(i+1));
            b1[j]=b[j]%(1<<(i+1));
        }
        sort(b1,b1+n);
        sum=0;
        for(int j=0;j<n;j++){
            int s1=lower_bound(b1,b1+n,(1<<i)-a1[j])-b1;
            int t1=lower_bound(b1,b1+n,2*(1<<i)-a1[j])-b1;
            int s2=lower_bound(b1,b1+n,3*(1<<i)-a1[j])-b1;
            int t2=lower_bound(b1,b1+n,4*(1<<i)-a1[j])-b1;
            sum+=(t1-s1)+(t2-s2);
        }
        if(sum&1)
            ans+=(1<<i);
    }
    PF("%d",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值