当N非常大时,从1到N的所有数字的数字的xor之和

时间:2016-12-17 08:33:11

标签: algorithm dynamic-programming

给定1和N,我们需要找到从1到N的所有数字的数字的XOR值之和, 例如,对于N,我们需要计算函数F

F(k){
    ans =0;
    while(k>0){
      ans= ans^(k%10);
      k/=10;
   }
   return ans;
}

表示[1,N]中的K.

有没有一种有效的方式可以说。 据我所知,我们应该计算V值使用DP产生XOR的次数,但我不能想到实现它的方法。

请给出一些想法。

示例:F(37)= 3 ^ 7 = 4

注意:N可以大到10 ^ 18

2 个答案:

答案 0 :(得分:0)

天真的方法花费O(N*log10(N))时间,通过简单的优化,您可以获得O(N)运行时。这个想法是:

k位数字的所有数字的XOR =第一个(k-1)个数字的XOR ^最后一个数字。

显然,您可以通过将数字除以10来找到第一个k - 1位数,因此关系变为:

F(i) = F(i / 10) ^ (i % 10)

代码:

result = 0
for i = 1:N
  dp[i] = dp[i/10] ^ i%10
  result += dp[i]

答案 1 :(得分:0)

  • 让我们计算一个稍微不同的东西:从1到N的数字对于所有X,其数字的xor等于X from 0 to 15

  • 一旦我们知道,问题的答案就是所有有效count[X] * X的{​​{1}}总和。

  • 我们如何有效地计算它?我们将使用标准的逐位动态编程

  • 我们可以将所有数字视为字符串。如果我们用零填充它们以使它们的长度等于X中的数字位数,我们可以按字典顺序对它们进行比较。

  • 动态编程的状态为:N - 以xor为(prefixLength, curXor, isSmaller)的方式放置第一个prefixLength个最高有效数字的方式数。如果此前缀小于curXor的前缀,则isSmaller为true。否则,前缀等于N的前缀。

  • 转换是再增加一位数。 N变化很简单。 curXor增加1。如果prefixLength为真,我们可以放置任何数字并继续。否则,我们不能在isSmaller中放置比此位置的数字更大的数字。如果我们放同一个,N保持错误。否则,它就变成了现实。

  • isSmallerL中的位数。比N范围内的数字xor等于f(L, X, 0) + f(L, X, 1)的确切X数字。

  • 我们完成了!状态数大约为16 * L * 2,转换次数约为16 * L * 2 * 10.作为[1, N],此解决方案的时间复杂度为L = O(log N),看起来相当不错。

这个解决方案背后的想法是标准的:当我们需要计算给定范围内有多少个具有特定属性(如数字之和,xor或其数字的其他函数)时,我们将数字放在一个 - 从最重要到最不重要的一个并跟踪3个参数:(已经放置的位数,前缀小于O(log N)的前缀,一些特定于问题的数据)。