avatar
fireworks99
keep hungry keep foolish

异或寻异

关于异或

a为任意数字:

0 ^ a = a

a ^ a = 0

给出n个数字, 有一个数字只出现奇数次,其余出现偶数次,找出这个数字

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

int a[1000005];

int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        if(n == 0)
            break;
        int ans = 0;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d", &a[i]);
            ans ^= a[i];
        }
        cout << ans << '\n';
    }
    return 0;
}

给出n个数字,有两个数字只出现奇数次,其余出现偶数次,找出这两个数字

更多解析 https://www.jianshu.com/p/cb400b455772

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int a[1000005];

int find_pos(int tem)
{
    int pos = 0;
    while(!(tem & 1))
    {
        tem >>= 1;
        pos++;
    }
    return pos;
}

int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        int ans = 0;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d", &a[i]);
            ans ^= a[i];
        }
        int res = ans;
        int pos = find_pos(ans);
        for(int i = 0; i < n; ++i)
        {
            if((a[i] >> pos) & 1)
                ans ^= a[i];
        }
        res ^= ans;///ÎÞÐòÊä³ö
        cout << ans << ' ' << res << '\n';
    }
    return 0;
}

给出n个数字,有三个数字只出现一次,其余出现两次,找出这三个数字

设f(n)为n最低位1所在位。

全部异或一次,得 x = a ^ b ^ c.(倘若保证 x != 0问题就像上面一样简单了)

x 不是 a、b、c 中的任一个

(反证:假设x = a, 由 a = a ^ b ^ c 得 b ^ c = 0, 得 b = c, 与题目矛盾)

所以 x ^ a, x ^ b, x ^ c 都不为0,所以f(x ^ a), f(x ^ b), f(x ^ c)都不为0,

那么 y = f(x ^ a) ^ f(x ^ b) ^ f(x ^ c) 也不为0

所以 y 的二进制至少有一位是1,假设其最低位1在M位上

f(x ^ a) f(x ^ b) f(x ^ c) y
0 0 0 0
1 0 0 1
1 1 0 0
1 1 1 1

有以下两种情况:

1.f(x ^ a),f(x ^ b),f(x ^ c)三个式子中只有一个,其第M位是1

2.三个式子第M位皆为1(倘若仅两个式子第M位为1,y的第M位是0)

第二种情况是错误的,反驳如下:

假设2成立,那么 (x ^ a) ^ (x ^ b) ^ (x ^ c) 其第M位 = 1^1^1 = 1,然而

(x ^ a) ^ (x ^ b) ^ (x ^ c) = x ^ x ^ x ^ (a ^ b ^ c) = x ^ x ^ x ^ x第M位为0

根据结论 x ^ a, x ^ b, x ^ c三个式子只有一个,其第M位为0 找到一个数字,再按前面的方法找另两个

Code

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

///a为任意数字:
/// 0 ^ a = a
/// a ^ a = 0
int a[1000005];

int find_pos(int tem)
{
    if(tem == 0)
        return 0;
    int pos = 1;
    while(!(tem & 1))
    {
        tem >>= 1;
        pos++;
    }
    return pos;
}

int main()
{
    int n;
//    freopen("00in.txt", "r", stdin);
    while(~scanf("%d", &n))
    {
        int first = 0;
        int second, third;
        int x = 0;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d", &a[i]);
            x ^= a[i];
        }
        ///找 f(x ^ a) ^ f(x ^ b) ^ f(x ^ c)
        int y = 0;
        for(int i = 0; i < n; ++i)
        {
            int t = x ^ a[i];
            int tem = find_pos(x ^ a[i]);
            y ^= tem;
        }

        int M = find_pos(y);
        ///利用结论找到第一个特别的数字
        for(int i = 0; i < n; ++i)
        {
            if((   find_pos(x ^ a[i])>>(M - 1)   )  &  1)
                first ^= a[i];
        }
        ///问题简化
        int ans = x ^ first;
        int t = ans;
        ///first丢到后面去
        for(int i = 0; i < n; ++i)
        {
            if(a[i] == first)
            {
                swap(a[i], a[n - 1]);
                break;
            }
        }
        ///找剩余两个数字
        int pos = find_pos(ans);
        for(int i = 0; i < n - 1; ++i)
        {
            if((a[i] >> (pos - 1)) & 1)
                ans ^= a[i];
        }
        second = ans;
        third = t ^ ans;///此输出无序
        cout << first << ' ' << second << ' ' << third << '\n';
    }
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy