【트리 트리】 | AcWing 143. 가장 큰 XOR 쌍

제목 설명

주어진 N 개의 정수 A 1 , A 2 …… A N 중 두 개를 선택 하여 xor (배타적 OR) 연산 수행합니다. 얻은 가장 큰 결과는 무엇입니까?

입력 형식
첫 번째 줄에 정수 N을 입력합니다.

두 번째 줄 N 정수 A 1~ A N을 입력하십시오 .

출력 형식
답을 나타내는 정수를 출력합니다.

데이터 범위

1≤N≤10 5 ,
0≤A i <2 31

입력 샘플 :

3
1 2 3

샘플 출력 :

사고 분석

0≤A i <2 31 , 즉 최대 값은 2 31-1 , 즉 31 개의 1이므로 정수의 최대 이진 표현은 31 비트입니다. 즉, 다음과 같은 이진 문자열이 될 수 있습니다. 길이가 31 비트이므로 차이는 OR 연산의 최대 결과는 1111 …… 11 (31 1)입니다.

XOR의 특성에 따라 차이는 1이고 같음은 0 이므로 두 개의 십진수 a^ba와 b가 선택된 a와 b의 각 이진수가 서로 다를 때 결국 가장 큰 XOR 결과를 얻습니다. (31 1) .
만약 그렇다면 우리는 이것을 할 수 있습니다. 우리가 검색 할 때마다 우리는 현재 a i 와 반대되는 위치 로 갈 것입니다. , XOR 값을 가장 크게 할 것입니다. 갈 방법이 없다면, 그러면 같은 방식으로 가십시오.

XOR 쌍을 찾는 프로세스 :

찾기는 상호 과정입니다. a로 b를 찾는 것은 a로 b를 찾는 것과 같습니다. 따라서 여러 숫자와 일치하는 숫자를 찾는 대신 여러 숫자로 숫자를 일치시키는 것이 좋습니다.
먼저 첫 번째 숫자를 저장 A 1 트리 트리 (초기화) 이면 A 2 는 Trie 트리에서 A 1 과만 일치 할 수 있습니다. 일치 후 A 2는 Trie 트리에 추가되고 A 3 은 Trie 트리에서 A 1 또는 A 2 와만 일치 할 수 있습니다. 결과가 가장 클 수 있고 그 다음이 4 ...... 등등, 최대 N이 될 수 있습니다.

  1. A x 와 Trie 트리에서 A 1 과 A x-1 사이의 숫자를 일치 시키고 ② A x 는 Trie 트리에 합류합니다. ①②이 둘의 순서는 필요하지 않습니다. A x가 먼저 Trie 트리에 삽입 되어도 자신과 자신의 매칭 결과가 0이므로 효과가 없지만 먼저 매칭 한 다음 삽입하는 것이 좋습니다. .
  2. 통상의 연속이어야 X. 1 + X (A)에 N의 사이의 번호 , 즉 정합 . 1 및 제 1A 2 (A)에 N 일치하는 개수하는 사이에 2 , 및 . 3 (A)에 N의 개수 그러나 Trie 트리를 삽입하는 것은 편리하지 않으므로 역사 고를 채택합니다.

문제의 핵심 :

1. 이진수는 Trie 트리에 저장됩니다.

이진수에는 0과 1 만 있으므로 분기가 두 개뿐입니다.

각 십진수는 이진수에 고유하게 대응하므로 레벨 1부터 레벨 31까지의 Trie 트리에서 한 분기가 다른 한 완전히 다른 숫자가 선택됩니다.
가장 큰 결과를 얻으려면 가장 높은 위치 에서 시작한 다음 가장 낮은 위치로 이동하여 가장 높은 위치를 전제로 최상의 솔루션을 찾아야합니다.

예 :x = (10010) 2 이면 최대 XOR은 (01101) 2 여야하며 모두 1입니다.
(01101)가있는 경우 2 에서 트라이 트리 , 다음 경기는 높은 위치 또는 낮은 위치에서 시작하고, 경기는 (01101)는 2 ;
하지만 트라이 트리가없는 경우 트리는 트리의 가장 큰 경우 (01000) 2 , 0 번째 비트와 2 번째 비트는 동일하고 다른 비트는 다릅니다. 가장 높은 비트부터 시작하면 (01000) 2를 찾을 수 있지만 가장 낮은 비트에서 일치하는 경우 가장 낮은 0은 Trie 트리에서 1로 이동합니다 . 어쨌든 (01000) 2 와 일치하지 않습니다 .

2. 검색 과정

숫자 x가 주어지면 Trie 트리에서 가장 큰 XOR 쌍을 찾으십시오. 가장
높은 비트에서 시작하고 검색 할 때마다 현재 a i반대 위치로 이동합니다. , XOR 값을 가장 크게합니다. , 갈 길이 없으면 같은 길로 가십시오.

3. 정수를 31 비트 이진 표현으로 분할

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

가장 높은 비트부터 시작하여 한 번에 한 비트 씩 가져옵니다.
그리고 여기에는 다른 숫자가 아닌 1 또는 0 만 사용할 수 있으므로 다음과 같이 쓸 수 없습니다.t=x&(1<<i);

암호

분석 2 31 ,
2 10 및 10 3은 근사치이므로 2 30 은 10 9 와 거의 유사합니다. 즉 , 1e9, 2 31은 약 2e9, 3e9 미만이면 int 유형을 사용하여 2 차원 트리를 정의 할 수 있습니다. 정렬.

#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