异或

异或


题目原链接:https://www.nowcoder.com/practice/fc05f68c5f47438db54c6923ef23cf4a?tpId=85&&tqId=29876&rp=3&ru=/activity/oj&qru=/ta/2017test/question-ranking

1.题目描述

给定整数m以及n各数字A1,A2,..An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大于m的有多少个。

2.输入描述

第一行包含两个整数n,m.
第二行给出n个整数A1,A2,...,An。
数据范围:
对于30%的数据,1 <= n, m <= 1000
对于100%的数据,1 <= n, m, Ai <= 10^5

3.输出描述

输出仅包括一行,即所求的答案

4.示例

输入

3 10  
6 5 10

输出

2

5.解题思路

参考链接:https://blog.csdn.net/qq_30507287/article/details/68947863

考虑用字典树来解决该题,用示例中6、5、10来构建一颗如下字典树(虚线表示不用):

graph TB
root-->0
root-->1
0-.->00(0)
0-->01(1)
01-->010(0)
01-->011(1)
011-->0110(0)
011-.->0111(1)
010-.->0100(0)
010-->0101(1)
1-->10(0)
1-.->11(1)
10-.->100(0)
10-->101(1)
101-->1000(0)
101-.->1001(1)

从已有的数据中选一个数记为a,遍历该字典树(二叉树),求所有与a异或大于m的数的个数,分情况讨论:

  • 如果a的当前位为0,m的当前位为0,那么明显父节点的右子树的所有数与a异或都大于m;但左子树不能确定,需要继续查询。
  • 如果a的当前位为1,m的当前位为0,那么明显父节点的左子树的所有数与a异或都大于m;但右子树不能确定,需要继续查询。
  • 如果a的当前位为0,m的当前位为1,那么明显父节点的左子树中的数和a异或一定小于m,查询结束;右子树的数不能确定,需要继续查询。
  • 如果a的当前位为1,m的当前位为1,那么明显父节点的右子树中的数和a异或一定小于m,查询结束;左子树的数不能确定,需要继续查询。

具体求解过程如下:

  • (1)依次读取n,m,将n个数依次放入数组并且构建对应的字典树。
  • (2)获取获取数组中的数,查询字典树,计算与其异或值大于m的数的个数。
  • (3)得到的count除2,因为如果a^b大于m,那么b^a也会大于m。

6.实现代码

*
*@bref:暴力求解,好像是可以通过80%,果然暴力还是不行
*
int main()
{
    int n,m,i,j,result,count=0,*value;
    cin>>n>>m;
    value=new int[n];
    
    for(i=0;i<n;i++)
    {
        cin>>value[i];
    }
    for(i=0;i<n-1;i++)
    {
        for(j=i+1;j<n;j++)
        {
            result=value[i]^value[j];
            if(result>m) count++;
        }
    }
    cout<<count<<endl;
    return 0;
}

能通过的解法:

#include<iostream>
using namespace std;
/*
* @bref:参考了大神们的思路,服气
*       了解字典树之后,理解这个题的解法就好多了
*/

//定义字典树节点
class trieTree
{
    public:
      int num;
      trieTree *son[2];
    public:
      trieTree(int num) 
      {
          this->num=num;
          son[0]=nullptr;
          son[1]=nullptr;
      }
};

int foo;
static void insert(int a,trieTree *current)
{
    //插入每一个节点,17位所能表示的最大值位131071
    for(int i=16;i>=0;i--)
    {
        foo=(a>>i)&1;//获取对应的位
        if(current->son[foo] == nullptr)
        {
            current->son[foo]=new trieTree(0);
        }
        current=current->son[foo];
        current->num++;//记数加1
     }
}

//查询结果
static int query(trieTree *root,int a,int m,int i)
{
    if(root==nullptr) return 0;
    
    trieTree *current=root; 
    int aDigit=(a>>i)&1;
    int mDigit=(m>>i)&1;
    if(aDigit==0 && mDigit==0)
    {
        int p=(current->son[1]==nullptr? 0:current->son[1]->num);
        int q=query(current->son[0],a,m,i-1);
        return p+q;
    }
    else if(aDigit==1 && mDigit==0)
    {
        int q=(current->son[0]==nullptr? 0:current->son[0]->num);
        int p=query(current->son[1],a,m,i-1);
        return p+q;
    }
    else if(aDigit==0 && mDigit==1)
    {
        if(current->son[1]==nullptr) return 0;
        return query(current->son[1],a,m,i-1);
    }
    else if(aDigit==1 && mDigit==1)
    {
        if(current->son[0]==nullptr) return 0;
        return query(current->son[0],a,m,i-1);
    }
    return 0;
}

int main()
{
    int m,n,*data;
    long count=0;
    trieTree root(-1);
    
    cin>>n>>m;
    data=new int[n];

    for(int i=0;i<n;i++)
    {
        cin>>data[i];
        insert(data[i],&root);//将所有的数
    }
       
    for(int i=0;i<n;i++)
    {
        count+=query(&root,data[i],m,16);
    }
    cout<<count/2<<endl;
    return 0;
}

6.思考与分析

这种题目的第一思路是暴力求解,虽然很大概率是不行的,但不妨一试,能想出合理高效的求解方案不是每一个人都能做到的,问题的抽象能力、联想能力往往是解题的关键,常备知识,遇到问题才能直击痛点,庖丁解牛。
在写这个题的时候,我自己实现了代码,但是感觉完全没问题,然后提交之后一直只通过80%,我后来花了将近两天的时间近乎一直在想这个题,最后突然灵光发现是用来存结果的count值是int型,而实际结果要大于int型所能表示的范围。真的服气.......我发誓以后存结果的数一定用long。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 异或的作用:0+1=1 ,0+0=0或者1+1=0输入描述:第一行一个数字n第二行n个数字 输出描述:输出最多的...
    培根好吃阅读 1,841评论 0 0
  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 8,984评论 0 13
  • 位运算 位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,...
    IIronMan阅读 7,759评论 0 2
  • 滴答!滴答!时间在不停地流逝。时间把昨天的未来变成今天的过去。时间把经历变成照片。时间把年少的我们变老。时...
    曹栋阅读 611评论 0 1
  • 时代在进步,社会在发展。在节奏感越来越快的今天,人​‌‌们开始追求于健康的生活方式及更强壮的体魄。由此,越来越多的...
    maybelinny阅读 144评论 0 0