代码源:732、简单的异或问题

286 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情logo.png

题目描述

这是4月11日代码源div2的每日一题。

简单的异或问题 - 题目 - Daimayuan Online Judge

有一组整数 {0,1,2,…,2m−1} 请从中选出 k 个数,使得这 k 个数的异或和为 n, 请输出最大的满足条件的 k。

输入格式

两个数 n 和 m, 其中 0≤n≤2^m−1,1≤m≤60。

输出格式

输出最大的满足条件的 k。

样例输入

2 2

样例输出

3

样例解释

对于样例,我们可以选择 {0,1,3}。

问题解析

首先这有一个结论:0~2^m-1的所有数进行XOR运算后,得到的结果是0。我们来证明一下这个结论:

比如m=3时,一共是0 1 2 3 4 5 6 7,八个数,我们把他们首位组成一对,一共是4对:{0,7}{1,6}{2,5}{3,4}。

它们每一对内部进行XOR运算后的结果都是7,转化成二进制就是111,此时4个111进行XOR运算,得到的自然是0。

那么这个结论有什么用呢,我们知道111和111经过xor运算后会变成0,因为他们每一位上都是相等的,如果我们想通过111获得一个数,在这里假设我们想要的是3(二进制是011),那么就需要111和100进行XOR运算,发现了吗,100正好就是和3配对的另一个数:4.

所以,想在0~2^m-1里通过xor运算获得一个数a,就只用(2^m-1)和(2^m-1-a)进行xor运算即可,但这里要求的是最多能选多少数,我们可以把所有的数(除了目标a)都选上,真正有用的只有(2^m-1)和(2^m-1-a),至于其他的数经过运算后都会变成0.所以k能取到的最大值就是2^m-1。但有两个特殊情况,一个是a=0时,我们可以把所有的数都选上,即k=2^m,还有一个是m=1时,想获得0只能选0,想获得1可以两个都选。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>#define endl '\n';
typedef long long ll;
typedef pair<ll, ll> PII;
​
int main()
{
    
    ll n, m;
    cin >> n >> m;
    ll res = 1;
    res <<= m;
    if (m == 1 && n == 0)
    {
        cout << 1 << endl;
    }
    else if (m == 1&&n==1)
    {
        cout << 2 << endl;
    }
    else cout << (1LL)*(res - min(n,1LL)) << endl;
    return 0;
}