1. 程式人生 > >G - Vitya and Strange Lesson(字典樹 )

G - Vitya and Strange Lesson(字典樹 )

G - Vitya and Strange Lesson

CodeForces - 842D

題意:給你一個數組,讓數組裡面的值都異或一下x,並構成一個新的陣列,求這個陣列的mex

mex的含義:不在陣列中的最小正整數。

思路:

異或的交換律

1.首先我們知道,異或x之後得到的陣列將其再異或y值得到的陣列,其實就是原陣列異或(x^y)的結果。所以這裡我們沒有必要將原陣列進行變化。

異或的唯一性即 a^b=c 如果b,c確定則a就確定

2.我們將原陣列中不存在的數入樹。那麼對於每一個查詢temp,其實就相當於我們在樹上找一個值,使得這個值亦或temp最小。(如果此處不懂,請看最後面)

3.找出異或最小值即可

**那麼這個數的範圍怎麼確定呢?**題中所有資料的範圍都在0~3e5之間,即二進位制第25位之前的全為0,

所以陣列中的數與x異或後的數也都滿足第二進位制第25位之前的全為0,那麼所求的mex的二進位制的第25位之前也全為0,a^b=c b c滿足這樣,所以a的進位制的第25位之前也全為0,

即要求原陣列中不存在的數的範圍最下為2^25即可(這樣的1~25位的的二進位制所有情況全部列舉,答案肯定是與其中一個異或)

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=10000010;
const int maxval=524288;
int ans[40];
int book[maxval];
struct Node{
    int net[2];
    Node()
    {
        clear();
    }
    void clear()
    {
      net[0]=net[1]=-1;
    }
}node[maxn];
int top;
void clear_tree(int &top)//清空樹
{
    for(int i=0;i<=top;++i)
        node[i].clear();
    top=0;
}
int Getbit(int &val,int k)//val的第k位是多少
{
    if(val&(1<<(k-1)))
        return 1;
    return 0;
}
void Becomebit(int &val,int k,int BitVal)//將val的第k位變為BitVal
{
    if(BitVal)
        val=val|(1<<(k-1));
    else
        val=val&(~(1<<(k-1)));
}
void insert_node(int &val)//將val的二進位制位從高到低插入進字典樹內
{
    int now=0;
    for(int i=32;i;--i)
    {
        if(node[now].net[Getbit(val,i)]==-1)
            node[now].net[Getbit(val,i)]=++top;
        now=node[now].net[Getbit(val,i)];
    }
}
int dfs(int now,int bit,int k)//根據當前節點和位數返回下一個節點  並且記下選的位數
{
    if(~node[now].net[bit])
    {
        ans[k]=bit;
        return node[now].net[bit];
    }
    ans[k]=bit?0:1;
    return node[now].net[bit?0:1];
}
int Solve(int &val)//x的值不能改變
{
    int now=0;
    for(int i=32;i;--i)
    {
      now=dfs(now,Getbit(val,i),i);//this?
    }
    int res;
    for(int i=32;i;--i)
      Becomebit(res,i,ans[i]);
    return res;
}
int main()
{
    int x,n,m;
    scanf("%d %d",&n,&m);
    memset(book,0,sizeof(book));
    for(int i=0;i<n;++i)
    {
        int mid;
        scanf("%d",&mid);
        book[mid]=1;
    }
    x=0;
    for(int i=0;i<=maxval;++i)
        if(!book[i])
           insert_node(i);//this?
    while(m--)
    {
        int mid;
        scanf("%d",&mid);
        x^=mid;
        printf("%d\n",x^Solve(x));
    }
}

參考部落格 https://blog.csdn.net/mengxiang000000/article/details/77718605

為什麼與原陣列異或x後的陣列的mex不在原陣列中的數與x異或的最小值

假設現在陣列a與x異或得到陣列c 那麼因為異或的唯一性,不在陣列c的值構成的集合即為不在陣列a的值與x異或構成的集合,(因為在陣列a的值與x異或一定在陣列c中)
在這裡插入圖片描述