タイトル説明
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まで続けます。
- ①マッチの間の数A 1及びAはX-1の中A 、Xおよびトライ木;②A X参加トライ木。①②Thereは、Aが場合でもため、これら二つの順序は必要ではないXは第一トライ木に挿入され、自身と自身のマッチング結果が0であり、それは効果がありませんが、まだ最初の一致した後に挿入することが推奨されます。
- 通常のシーケンシャルであるべきである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;
}