2018.08.21 【校内模拟】T2 位运算 Xorand (01Trie)(贪心) (思维题)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/81908911

描述

有q次操作,每次操作是以下两种:

  1. 加入一个数到集合中
  2. 查询,查询当前数字与集合中的数字的最大异或值,最大and值,最大or值

输入

第一行1个正整数Q表示操作次数

接下来Q行,每行2个数字,第一个数字是操作序号OP(1,2),第二个数字是X表示操作的数字

输出

输出查询次数行,每行3个整数,空格隔开,分别表示最大异或值,最大and值,最大or值

样例输入

【输入样例1】

5
1 2
1 3
2 4
1 5
2 7

【输出样例1】

7 0 7
5 5 7

【样例解释1】

询问4时,已插入2、3,最大异或值为4^3=7,最大and值为4&3或4&2=0,最大or值为4|3=7
询问7时,已插入2、3、5,最大异或值为7^2=5,最大and值为7&5=5,最大or值为7|2=7|3=7|5=7

【输入样例2】

10
1 194570
1 202332
1 802413
2 234800
1 1011194
2 1021030
2 715144
2 720841
1 7684
2 85165

【输出样例2】

1026909 201744 1032061
879724 984162 1048062
655316 682376 1043962
649621 683464 1048571
926039 85160 1011199


BB:

做这道题的心路历程也真的是绝了。。。

先是隐约想出了and和or的正解写法,却不知道如何处理xor。。。

后来写了个 01 T r i e ,xor调过了,and和or又调不出来。。。

最后交了一个暴力。。。


解析:

相信xor大家应该都会。。。就是 o 1 T r i e 上面的贪心操作。

对于and,我们思考一下,当前数已经为0的位我们无能为力了对吧,所以我们只能在原数为1的位置上尽量多放1,而且越靠前越好。

那么,不就只需要维护一下有哪些位在同一个数中出现过就行了吗?

对于or,作类似考虑。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static

inline
ll getint(){
    st ll num;
    st char c;
    while(!isdigit(c=gc()));
    for(num=0;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
    return num;
} 

inline
void outint(ll a){
    st char ch[23];
    if(!a)pc('0');
    while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
    while(ch[0])pc(ch[ch[0]--]);
}

cs int M=(1<<21);
bool b[5000001];
bool mark[1<<22];

inline
void marksubset(int k){
    mark[k]=true;
    for(int re i=0;i<=19;++i){
        if((k&(1<<i))&&!mark[k^(1<<i)])marksubset(k^(1<<i));
    }
}

inline
void buildtrie(int k){
    k+=M;
    while(k){
        if(b[k])break;
        b[k]=true,k>>=1;
    }
}

inline
void ins(int k){
    if(!mark[k]){
        marksubset(k);
    }
    buildtrie(k);
}

inline
int queryxor(int k){
    int now=1;
    for(int re i=20;i>=0;--i){
        if(b[now<<1]==true&&b[now<<1|1]==false){
            now=now<<1;
        }
        else if(b[now<<1]==false&&b[now<<1|1]==true){
            now=now<<1|1;
            k^=(1<<i);
        }
        else if(b[now<<1]==true&&b[now<<1|1]==true){
            if((k&(1<<i))==0){
                now=now<<1|1;
                k^=(1<<i);
            }
            else{
                now=now<<1;
            }
        }
    }
    return k;
}

inline
int queryand(int k){
    int now=0;
    for(int re i=20;~i;--i){
        if((k&(1<<i))&&mark[now|(1<<i)])now|=(1<<i);
    }
    return now&k;
}

inline
int queryor(int k){
    int now=0;
    for(int re i=20;~i;--i){
        if(!(k&(1<<i))&&mark[now|(1<<i)])now|=(1<<i); 
    }
    return now|k;
}

int Q;
int main(){
    Q=getint();
    while(Q--){
        int op=getint();
        int num=getint();
        switch(op){
            case 1:{
                ins(num);
                break;
            }
            case 2:{
                outint(queryxor(num)),pc(' ');
                outint(queryand(num)),pc(' ');
                outint(queryor(num)),pc('\n');
                break;
            }
        }
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/81908911