Acwing- 143. 最大异或对

 暴力解法(超时了)

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n;
int a[N];

int main()
{
    cin >> n;
    for (int i = 0; i < n; ++ i) cin >> a[i];
    
    int res = 0;
    for (int i = 0; i < n; ++ i)
        for (int j = 0; j < n; ++ j)
            res = max(res, a[i] ^ a[j]);
            
    cout << res << endl;
    
    return 0;
}

暴力解法的思路是,固定一个数a[i](第一重循环),然后在a[1]-a[n]中选出a[j](第二重循环),使得a[i] ^ a[j] 最大。对于每个a[i]都能求出一个最大值,对所有情况再取一个max就是要求的答案。

如何优化上面的程序呢?

对于第一步枚举a[i]不是很好优化,所以我们把优化的重点放在第二步(即当a[i]固定时,如何在a[1]-a[n]中选出a[j],使得a[i]与a[j]的异或值最大)

举个栗子

总结一下:首先对所有的a[i](i从1到n)根据每一位的0/1建立Trie数组,对每个固定的a[i],从根往下走,每次尽量往跟我当前这一位不同的分支上走,如果存在这样的分支就走过去,如果不存在,只好走跟我当前分支的这一位相同的分支了,这样的话走到底就一定能够得到最优解。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = 3000000;

int n;
int son[M][2], idx;
int a[N];

void insert(int x)
{
    int p = 0;
    for (int i = 30; ~i; i --)
    {
        int &s = son[p][x >> i & 1];
        if (!s) s = ++ idx;  // 创建新节点
        p = s;
    }
}

// 找到和当前值异或值最大的结果
int query(int x)
{
    int res = 0, p = 0;
    for (int i = 30; ~i; -- i)
    {
        int s = x >> i & 1;
        if (son[p][!s])
        {
            res += 1 << i;
            p = son[p][!s];
        }
        else  p = son[p][s];
    }
    return res;
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; ++ i) 
    {
        cin >> a[i];
        insert(a[i]);   
    }
    
    int res = 0;
    for (int i = 0; i < n; ++ i) res = max(res, query(a[i]));
            
    cout << res << endl;
    
    return 0;
}

上述程序中,有个细节需要注意,int &s = son[p][x >> i & 1];

&的两种使用方法:一种是取地址符,一种是引用。

int a;
int *p = &a; 

上面这种就是取地址符,指针p指向变量a,p中存放的是a的地址 

int &c = b;

上面这是引用,定义一个引用就是说,c是b的一个别名,c就是代表b,改变c的值也就改变了b的值(注意:声明引用时必须要初始化,不能空声明,如:int &c是错的,int &c = b则可以)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

青衫客36

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

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

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

打赏作者

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

抵扣说明:

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

余额充值