介绍
0和1之间的每个有理数都可以表示为最终的周期性位序列。例如,11/40的二进制表示为
0.010 0011 0011 0011 ...
0011
无限期重复的部分。以下是找到此表示形式的一种方法。从r = 11/40开始,然后重复将其加倍并取小数部分,当它超过1时进行记录。当r的值重复时,您就知道已经进入循环。
1. r = 11/40
2. 2*r = 11/20 < 1 -> next bit is 0, r = 11/20
3. 2*r = 11/10 >= 1 -> next bit is 1, r = 2*r - 1 = 1/10
4. 2*r = 1/5 < 1 -> next bit is 0, r = 1/5
5. 2*r = 2/5 < 1 -> next bit is 0, r = 2/5
6. 2*r = 4/5 < 1 -> next bit is 0, r = 4/5
7. 2*r = 8/5 >= 1 -> next bit is 1, r = 2*r - 1 = 3/5
8. 2*r = 6/5 >= 1 -> next bit is 1, r = 2*r - 1 = 1/5, same as in 4.
The loop 5. -> 6. -> 7. -> 8. now repeats.
要从二进制字符串返回到11/40,可以使用以下公式
(int(prefix) + int(suffix)/(2^len(suffix) - 1)) / 2^len(prefix)
where prefix
是初始部分010
,suffix
是重复部分0011
,int
并将二进制字符串转换为整数。
给定两个这样的表示,我们可以对它们执行按位XOR操作。结果序列也将是周期性的,因此它表示一个有理数。
对于某些有理数,有两种二进制表示形式。
1/4 = 0.010000000...
= 0.001111111...
它们之间的选择会影响按位异或的结果。在这些情况下,我们使用前一个表示形式,该表示形式具有无限多个0。
任务
您的输入是半开区间[0,1)中的两个有理数。您的输出应为应用于输入的按位XOR运算的结果,以有理数表示。请注意,即使两个输入都不是,输出也可以为1。
输入和输出的确切格式是灵活的,但每个有理数应该由两个整数分子和分母(具有0和1之外,其可以被表示为被表示0
和1
如果需要的话)。您可以假设输入用最低术语表示。输出必须用最低的术语表示。内置有理数类型是可以接受的格式,只要它满足这些限制。您可以忽略语言所强加的整数的任何界限,但理论上,算法应适用于所有有理数。
最低字节数获胜。适用标准代码高尔夫球规则。
例
考虑输入11/40和3/7。我们将它们的表示形式一个接一个地写,用管道将重复的部分定界|
。然后,我们提取相等长度的重复部分,并对它们和它们之前的部分进行按位XOR。
11/40 = 0. 0 1 0|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 ...
3/7 = 0.|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|...
-> 0. 0 0 1|0 1 0 1 1 1 1 0 1 0 0 0|0 1 0 1 1 1 1 0 1 0 0 0|0 1 0 ...
所得的有理数为89/520。
测试用例
0 0 -> 0
1/2 1/2 -> 0
1/2 1/4 -> 3/4
1/3 2/3 -> 1
1/2 3/4 -> 1/4
5/8 1/3 -> 23/24
1/3 1/5 -> 2/5
15/16 3/19 -> 257/304
15/16 257/304 -> 3/19
3/7 11/40 -> 89/520
5/32 17/24 -> 59/96
16/29 16/39 -> 621001733121535520/696556744961512799
000...
在这种情况下结束的表示形式(如果将算法与一起使用,这也是得到的结果r
)。例如,在这种情况下5/8, 1/3
,23/24
由于我们选择的展开0.101000...
,所以我们得到了5/8
。如果我们选择0.10011111...
as作为5/8
,则XOR之后的结果变为19/24
,所以这是错误的。有关维基百科:0.999 ...
(a ^ b) ^ b == a
它不成立。例如(19/24 ^ 1/3) ^ 1/3 != 19/24
。这让我对此非常兴奋:(