【问题标题】:XOR programming puzzle adviceXOR 编程难题建议
【发布时间】:2017-01-11 02:19:26
【问题描述】:

给定一个long int x,统计满足以下条件的a值的个数:

a XOR x > x
0 ax

其中 ax 是长整数,XOR 是按位异或运算符

你将如何解决这个问题?

我还应该提到,输入 x 可以大到 10^10

我已经设法通过迭代 0 到 x 检查条件并增加计数值来获得蛮力解决方案..但这不是最佳解决方案...


这是我尝试过的蛮力。它可以工作,但对于较大的 x 值非常慢。

 for(int i =0; i < x; i++)
 {
      if((0 < i && i < x) && (i ^ x) > x)
          count++;    
 }

【问题讨论】:

  • 如果投反对票的人可以提及他们投票的原因,那就太好了,否则我们将不得不称他们为尴尬。
  • 不是downvoter,但这与编程无关。这是关于需要证明的数字的数学事实。
  • 对于 x > 0,a 中为 1 且 x 中为 0 的任何位都会导致 a ^ x > x,除了 MSB 会导致它为负数。
  • 好的,这里有一个提示。假设您知道某个数字x 的答案。你现在能计算出2x 的答案吗? 2x+1呢?
  • (0 &lt; i &amp;&amp; i &lt; x) 中的 if() 完全是多余的。删除它和/或使用-O2 编译,您应该会在几秒钟内得到结果。

标签: c++ xor bits


【解决方案1】:
long long NumberOfA(long long x)
{
    long long t = x <<1;
    while(t^(t&-t)) t ^= (t&-t);
    return t-++x;
}


long long x = 10000000000;
printf("%lld ==> %lld\n", 10LL, NumberOfA(10LL) ); 
printf("%lld ==> %lld\n", x, NumberOfA(x) ); 

输出

10 ==> 5
10000000000 ==> 7179869183

Link to IDEOne Code


试图解释逻辑(使用示例 10,或1010b

  • 将 x 向左移动 1。(值 20 或 10100b
  • 关闭所有低位,只保留高位(值 16 或 10000b
  • 减去 x+1 (16 - 11 == 5)


试图解释
(虽然不容易)

您的规则是a ^ x 必须大于x,但您不能向ax 添加额外的位。
(如果以 4 位值开头,则只能使用 4 位)

N 位数字的最大可能值为2^n -1
(例如,4 位数字,2^4-1 == 15)
让我们拨打这个号码B

在您的值 xB(含)之间,存在 B-x 可能的值。
(回到我的示例, 10。在 15 到 10 之间,有 5 个可能的值:1112131415)

在我的代码中,tx &lt;&lt; 1,然后关闭所有低位。
10 &lt;&lt; 120;关闭所有低位以获得 16 )

那么 16 - 1BB - x 是你的答案:
t - 1 - x,t - ++x 相同,就是答案)

【讨论】:

  • 然而,这为 10000000000 提供了一个不正确的答案 (AFAIK),它应该是 7179869183 但我得到的是 737418239
  • 我的最新版本得到:7,179,869,183
  • 这可能是我在很长一段时间内完成的最丑陋、最奇怪的位操作代码。 :) 有趣的问题!
  • 哈哈,你介意解释一下你是如何得到这个答案的,比如你的想法是什么等。谢谢
  • 投反对票?想发表评论?
【解决方案2】:

看待这个问题的一种方法是考虑 x 中的每一位。

  • 如果是 1,那么翻转它会产生一个较小的数字。
  • 如果它是 0,那么翻转它会产生一个更大的数字,我们应该计算它 - 以及右边的所有位组合。这很方便地添加到掩码值。
long f(long const x)
{
    // only positive x can have non-zero result
    if (x <= 0) return 0;

    long count = 0;

    // Iterate from LSB to MSB
    for (long mask = 1;  mask < x;  mask <<= 1)
        count += x & mask
            ? 0
            : mask;

    return count;
}

我们可能会怀疑这里有一种模式 - 看起来我们只是在复制 x 并翻转它的位。

让我们使用最小的测试程序来确认:

#include <cstdlib>
#include <iostream>

int main(int, char **argv)
{
    while (*++argv)
        std::cout << *argv << " -> " << f(std::atol(*argv)) << std::endl;
}
0 -> 0
1 -> 0
2 -> 1
3 -> 0
4 -> 3
5 -> 2
6 -> 1
7 -> 0
8 -> 7
9 -> 6
10 -> 5
11 -> 4
12 -> 3
13 -> 2
14 -> 1
15 -> 0

所以我们要做的就是“涂抹”该值,以便设置最重要的 1 之后的所有零位,然后与之异或:

long f(long const x)
{
    if (x <= 0) return 0;
    long mask = x;
    while (mask & (mask+1))
        mask |= mask+1;
    return mask ^ x;
}

这要快得多,而且仍然是 O(log n)。

【讨论】:

  • 这也是一个很好的解决方案,有很好的解释,谢谢。
猜你喜欢
  • 2020-03-03
  • 1970-01-01
  • 2021-03-02
  • 2012-01-21
  • 1970-01-01
  • 2013-06-01
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
相关资源
最近更新 更多