异或和快速求法

异或和快速求法

题目描述

给定一个数组[a1,a2,a3…an][a_1, a_2, a_3 \dots a_n][a1,a2,a3an] , 定义f(i,j)f(i,j)f(i,j)aiXORaja_i\quad XOR\quad a_jaiXORaj

求任意 i,ji,ji,j , f(i,j)f(i,j)f(i,j) 的和

比较传统的做法

传统做法就是直接暴力枚举,即双重循环

#include<bits/stdc++.h>
using namespace std;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int Sum = 0;
    for(int temp = 0 ; temp < 10 ; temp++){
        for(int temp2 = temp ; temp2 < 10; temp2++){
            if(temp == temp2) continue;
            Sum += (arr[temp] ^ arr[temp2]);
        }
    }
    cout << Sum;
    return 0;
}

// 339

但此时复杂度来到了不能接受的 O(n2)O(n^2)O(n2) , 所以我们有了一个更优的算法

更优的算法

众所周知,异或是一个位运算,所以我们可以将要异或的数展开来看:

[1,2,3,4,5,6,7,8,9,10][1,2,3,4,5,6,7,8,9,10][1,2,3,4,5,6,7,8,9,10] 举例:

111 [[[ 000 000 000 111 ]]] 222 [[[ 000 000 111 000 ]]]

333 [[[ 000 000 111 111 ]]] 444 [[[ 000 111 000 000 ]]]

555 [[[ 000 111 000 111 ]]] 666 [[[ 000 111 111 000 ]]]

777 [[[ 000 111 111 111 ]]] 888 [[[ 111 000 000 000 ]]]

999 [[[ 111 000 000 111 ]]] 101010 [[[ 111 000 111 000 ]]]

之后我们统计每一个位上 111 的个数:

[[[ 333 444 555 555 ]]]

我们可以知道,这些数异或和的值取决于每个位(1,0)(1,0)(1,0)对的个数,所以我们对每个位计算(1,0)(1,0)(1,0)对的个数

根据乘法法则得:

[[[ (3×7)(3\times 7)(3×7) (4×6)(4\times6)(4×6) (5×5)(5\times 5)(5×5) (5×5)(5\times5)(5×5) ]]]

所以他们的异或和为:

21×23+24×22+25×21+25×20=33921\times 2^3 + 24\times 2^2 + 25\times 2^1 + 25\times 2^0 = 33921×23+24×22+25×21+25×20=339

代码

#include<bits/stdc++.h>
using namespace std;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int Count[10];
signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    for(int temp = 0 ; temp < 10 ; temp++){
        for(int temp2 = 0 ; temp2 <= 5 ; temp2++){
            if((arr[temp] >> temp2) & 1)
                Count[temp2] ++;
        }
    }
    int Sum = 0;
    for(int temp = 0 ; temp <= 5 ; temp++)
        Sum += ((Count[temp] * (10 - Count[temp])) * (1 << temp));
    cout << Sum;
    return 0;
}

XOR补充知识

x⊕y=z⇒x⊕z=yx\oplus y = z \Rightarrow x \oplus z = yxy=zxz=y

(x⊕y)⊕z=x⊕(y⊕z)(x \oplus y) \oplus z = x \oplus (y \oplus z)(xy)z=x(yz)

x⊕0=xx⊕x=0x \oplus 0 = x \quad\quad x\oplus x = 0x0=xxx=0

x⊕b⊕b=x⊕0=xx \oplus b \oplus b = x \oplus 0 = xxbb=x0=x

完结撒花

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yyym__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值