给定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
答案 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
保持错误。否则,它就变成了现实。
让isSmaller
为L
中的位数。比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)
的前缀,一些特定于问题的数据)。