• [HDU-4825] Xor-Sum (01字典树)


    Problem Description

    Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。你能证明人类的智慧么?


    Input

    输入包含若干组测试数据,每组测试数据包含若干行。
    输入的第一行是一个整数T(T < 10),表示共有T组数据。
    每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。


    Output

    对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
    对于每个询问,输出一个正整数K,使得K与S异或值最大。


    Sample Input

    2
    3 2
    3 4 5
    1
    5
    4 1
    4 6 5 6
    3


    Sample Output

    Case #1:
    4
    3
    Case #2:
    4


    Source

    2014年百度之星程序设计大赛 - 资格赛

    Solution

    本蒟蒻的第一道 01字典树的题目,算是了解了这个数据结构.

    1. 插入
      操作如平常的 Tire 树,每次都通过这个树的二进制下位来确定位置.
      同时另开一个数组表示节点.再最后打一个标记大小.

    2. 查询
      每一次只要找和自己这一位不同的即可,如果有,那么就继续沿着走,否则就走相同的. 如果已经没有路可走了,那么直接返回值.

    然后对着别人板子打了一波,代码如下.

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 100000 + 5;        
    typedef long long ll;
    ll c[maxn],n,m;
    int ch[32 * maxn][2];             
    ll value[32 * maxn];                
    int node_cnt;                       
    
    inline void init()
    {                 
        node_cnt = 1;
        memset(ch[0],0,sizeof(ch));
    }           
    
    inline void insert(ll x){           
                                        
        int cur = 0;
        for(int i=32;i>=0;i--)
    	{
            int idx=(x>>i)&1;
            //取出在 32 位下的每一位
    		//所以这也是为什么开32倍的数组 
            if(!ch[cur][idx])
    		{
                memset(ch[node_cnt],0,sizeof(ch[node_cnt]));
                //因为上次的还没清零. 
                ch[cur][idx]=node_cnt;
                //新建一个元素. 
                value[node_cnt++]=0; 
                //尚未结束,打的标记是整个数的大小. 
    		}
                cur=ch[cur][idx];
        }
        value[cur]=x;           
    }
    
    inline ll query(ll x)
    {              
        int cur=0;
        for(int i=32;i>=0;--i)
    	{
            int idx=(x>>i)&1;
            if(ch[cur][idx^1]) cur=ch[cur][idx^1];
            //因为是按位与 所以就要取反. 
            else cur = ch[cur][idx];
        }
        return value[cur];
    }
    
    int main()
    {
    	int t; scanf("%d",&t);
    	for(int i=1;i<=t;i++)
    	{
    		init();
    		scanf("%lld%lld",&n,&m);
    		for(int j=1;j<=n;j++)
    		{scanf("%lld",&c[j]); insert(c[j]);}
    		//插入每一个数. 
    		cout<<"Case"<<' '<<'#'<<i<<':'<<endl;
    		while(m--)
    		{
    			int x; scanf("%d",&x);
    			cout<<query(x)<<endl;
    		}
    	}
    } 
    
  • 相关阅读:
    前端全链路优化总结
    到底使用字符数组还是字符串常量
    指针的误区
    指针
    函数使用初体验
    C语言函数使用小试牛
    十年研发经验工程师的嵌入式学习书籍大推荐与学习进阶路线
    TCP/IP协议前期的一知半解
    Ubuntu 16.04 LTS安装sogou输入法详解
    1/0信封——数据链路层,ARP及RARP
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9215650.html
Copyright © 2020-2023  润新知