【トライツリー】| AcWing143。最大のXORペア

タイトル説明

2つの選択与えられたNの整数A 1、A 2 ...... A NをするためにXOR(排他的論理和)演算を実行し、得られた最大の結果は何ですか?

入力形式
最初の行に整数Nを入力します

Nの整数A入力1〜AでNを二行目

出力形式
答えを表す整数を出力します。

データ範囲

1≤N≤10 5
0≦A I <2 31

入力サンプル:

3
1 2 3

サンプル出力:

3

思考分析

0≦A I <2 31であり、最大値は2で31 -1、31のものであるため、整数の最大バイナリ表現換言すると31ビットであり、それが持つバイナリ文字列になることができます長さは31ビットなので、差は次のようになります。OR演算の最大結果は1111……11 (31 1)

XORの性質によれば、差は1であり、同じものは0であるため、2つの10進数aとbはa^b、選択されたaとbの各2進数が互いに異なる場合、最終的に最大のXOR結果が得られます。(31 1)
この場合、これを行うことができます。検索するたびに、現在のa iと反対の位置に移動します。つまり、XOR値を最大にします。移動する方法がない場合は、同じように行きます。

XORペアを見つけるプロセス:

発見は、相互のプロセスであることで検索bはbで見つけることと等価であるので、代わりにいくつかの番号と一致する番号を見つける、いくつかの数字で番号を一致させる方が良いです。。
最初の店舗最初の数A 1トライ木(初期化)、次いで2のみができる一致Aで1トライ木に。マッチングした後、A 2は、トライ木に加え、次いでA 3が唯一でき一致Aと1又はA 2トライ木に、そして結果が最大になる可能性があることを見つけ、次に4 ......などをNまで続けます。

  1. マッチの間の数A 1及びAはX-1のA 、Xおよびトライ木;②A X参加トライ木。①②Thereは、Aが場合でもため、これら二つの順序は必要ではないXは第一トライ木に挿入され、自身と自身のマッチング結果が0であり、それは効果がありませんが、まだ最初の一致した後に挿入することが推奨されます。
  2. 通常のシーケンシャルであるべきであるA XおよびA 1 + X AにN個の間の数、即ちマッチングA 1と第1のA 2 AにNマッチの数、Aの間に2、及びA 3 AへのNの数の間で一致しますが、Trieツリーを挿入するのは不便なので、逆の考え方が採用されています。

問題の鍵:

1.2進数はTrieツリーに保存されます

2進数には0と1しかないため、分岐は2つだけです。

各10進数は2進数に一意に対応するため、レベル1からレベル31までのトライツリーでは、1つのブランチが異なる限り、完全に異なる番号が選択されます。
最大の結果を得るには、最も高い位置から始めて、最も低い位置に移動し、最も高い位置を前提として最適なソリューションを見つける必要があります。

例えばx =(10010)2の場合、その最大XORは(01101)2である必要があり、これはすべて1です。
(01101)がある場合、2トライ木、次に一致が高い位置又は低い位置から開始し、一致が(01101)である2 ;
しかし、誰トライ木が存在しない場合、トライ木において最大である場合(01000)2、0ビット目と2ビット目は同じであり、他のビットは異なっている。最上位ビットから始めて、あなたは(01000)見つけることができる2を、最低0必要がありますが、最下位ビットから一致した場合Trieツリーの1に移動します。これは、とにかく(01000)2とは一致しません

2.検索プロセス

数値xが与えられた場合、トライツリーで最大のXORペアを見つけます。
最上位ビットから開始し、検索するたびに、現在のa iと反対の位置に移動します。つまり、XOR値を最大にします。 、行く方法がない場合は、同じ方法で行きます。

3.整数を31ビットのバイナリ表現に分割します

int x,t;
for (int i=30;i>-1;i--)  t=x>>i&1; 

最上位ビットから開始し、一度に1ビットずつ取得します。
そして、ここでは1または0のみを取ることができ、他の数字は取ることができないため、次のように書くことはできません。t=x&(1<<i);

コード

2分析31
2 10及び10 3は2に、近似30があるとほぼ同様の10 9つまり、1E9、であり、2 31であり、約2E9、以下3e9より、あなたは二次元トライを定義するためにint型を使用することができアレイ。

#include <iostream>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=1e5+10;
int a[N];
int trie[N*32][2],idx=1; "idx为0的时候存储根节点,已经默认了,下一个结点从1开始"

void insert(int x)
{
    
    
    int p=0; //从根节点0开始插入
    for (int i=30;i>-1;i--) {
    
     "要保证异或结果最大,从最高位开始取,共31位,所以共取30次"
        int t=x>>i&1;  "这是一个处理过程,01串中取出每一位,每种字符串不一样,小写字母串就处理成t=a[i]-'a',映射成列坐标"
        if (!trie[p][t]) trie[p][t]=idx++;
        p=trie[p][t];
    }
}

int find(int x) //找到一个和x异或结果最大的异或对
{
    
    
    int p=0,res=0;
    for (int i=30;i>-1;i--) {
    
    
        int t=x>>i&1;
        if (trie[p][!t]) res+=1<<i,p=trie[p][!t]; "优先考虑走不同分支,使该位的值为1,并加上相应的值:1<<i"
        else p=trie[p][t];  "如果没有不同的分支,只能走相同的分支,那么该位就是0,不用加"
    }
    return res; //最后返回异或的结果
}

int main()
{
    
    
    int n;
    read(n);
    for (int i=0;i<n;i++) read(a[i]);
    insert(a[0]);
    int res=-1; "异或的结果必大于等于0"
    for (int i=1;i<n;i++) {
    
    
        res=max(res,find(a[i]));  //每次取最大的结果
        insert(a[i]);   "先比较,再插入Trie树"
    }
    printf("%d",res);
    
    return 0;
}

検索機能の異なる考え方、ビット演算の柔軟な使用:

int find(int x)
{
    
    
    int p=0,res=0;
    for  (int i=30;i>-1;i--) {
    
    
        int t=x>>i&1;
        if (trie[p][!t]) res=res*2+1,p=trie[p][!t];
        else res=res*2,p=trie[p][t];
    }
    return res;
}

最大のXOR結果を返すことに加えて、xとXORされた数を返すこともできます
res=max(res,a[i]^find(a[i]));

int find(int x)
{
    
    
    int p=0,y=0;
    for  (int i=30;i>-1;i--) {
    
    
        int t=x>>i&1;
        if (trie[p][!t]) y=y*2+!t,p=trie[p][!t];
        else y=y*2+t,p=trie[p][t];
    }
    return y;
}
int find(int x)
{
    
    
    int p=0,y=0;
    for  (int i=30;i>-1;i--) {
    
    
        int t=x>>i&1;
        if (trie[p][!t]) y+=!t<<i,p=trie[p][!t];
        else y+=t<<i,p=trie[p][t];
    }
    return y;
}

おすすめ

転載: blog.csdn.net/HangHug_L/article/details/114188474