感谢@TheDark发现溢出。新的C ++解决方案也非常有趣。这非常多余:
if(2*i > n && 2*i > i)
替换旧的代码行if(2*i > n)
。
我正在做this problem on HackerRank,虽然问题可能与此问题无关。如果您无法看到该网页,或者必须创建一个帐户但又不想这样做,则问题会在下面的纯文本中列出。
我的C ++代码超时,但我的python代码不是。我首先怀疑这是由于溢出造成的,但我使用sizeof
来确保unsigned long long
可以达到问题的上限2^64 - 1
。
我几乎将我的C ++代码直接翻译成Python,看看是不是我的算法导致超时,但令我惊讶的是我的Python代码通过了每个测试用例。
C ++代码:
#include <iostream>
bool pot(unsigned long long n)
{
if (n % 2 == 0) return pot(n/2);
return (n==1); // returns true if n is power of two
}
unsigned long long gpt(unsigned long long n)
{
unsigned long long i = 1;
while(2*i < n) {
i *= 2;
}
return i; // returns greatest power of two less than n
}
int main()
{
unsigned int t;
std::cin >> t;
std::cout << sizeof(unsigned long long) << std::endl;
for(unsigned int i = 0; i < t; i++)
{
unsigned long long n;
unsigned long long count = 1;
std::cin >> n;
while(n > 1) {
if (pot(n)) n /= 2;
else n -= gpt(n);
count++;
}
if (count % 2 == 0) std::cout << "Louise" << std::endl;
else std::cout << "Richard" << std::endl;
}
}
Python 2.7代码:
def pot(n):
while n % 2 == 0:
n/=2
return n==1
def gpt(n):
i = 1
while 2*i < n:
i *= 2
return i
t = int(raw_input())
for i in range(t):
n = int(raw_input())
count = 1
while n != 1:
if pot(n):
n /= 2
else:
n -= gpt(n)
count += 1
if count % 2 == 0:
print "Louise"
else:
print "Richard"
对我来说,两个版本看起来都一样。我仍然认为我在某种程度上被愚弄,实际上是在我的C ++代码中溢出,导致超时。
如果N不是2的幂,它们会将计数器的最大功率减小2,小于N.
如果N是2的幂,它们将计数器减少一半N.
结果值是新的N,它再次用于后续操作。
当计数器减少到1时游戏结束,即N == 1,最后一个进行有效移动的人获胜。
鉴于N,你的任务是找到比赛的胜利者。
输入格式
第一行包含一个整数T,即测试用例的数量。 T线跟随。每行包含N,即计数器中设置的初始数字。
约束
1≤T≤10
1≤N≤2^ 64 - 1
输出格式
对于每个测试用例,请在新行中打印获胜者的姓名。因此,如果路易斯赢得比赛,请打印“路易丝”。否则,打印“理查德”。 (行情是为了清晰起见)
示例输入
1
6
示例输出
理查德
解释
当6不是2的幂时,Louise减小2的最大幂,小于6,即4,因此计数器减少到2。
当2是2的幂时,理查德将计数器减少2的一半,即1.因此,计数器减少到1.
当我们达到N == 1的终止条件时,理查德赢得比赛。
答案 0 :(得分:4)
当n
大于2 ^ 63时,您的gpt
函数最终将i
设为2 ^ 63,然后将2 ^ 63乘以2,得到溢出值和值这将以无限循环结束,每次将0乘以2。
答案 1 :(得分:0)
试试这个有点笨拙的黑客攻击,这可能会稍快一些:
unsigned long largest_power_of_two_not_greater_than(unsigned long x) {
for (unsigned long y; (y = x & (x - 1)); x = y) {}
return x;
}
x&(x-1)
是x
,没有最不重要的一位。因此,当y
减少到2的幂时,x
将完全为零(终止循环),这将是不大于原始x的2的最大幂。对x
中的每1位执行一次循环,平均迭代次数是方法的一半。此外,这个没有溢出问题。 (如果原始x
为0,则返回0.这可能是您想要的也可能不是。)
请注意,如果原始x
是2的幂,则只需立即返回该值。因此,该函数兼作x
是2的幂(或0)的测试。
虽然这很有趣,但在实际代码中,您可能最好找到与此gcc
内置编译器等效的编译器(除非您的编译器是 {{ 1}},在这种情况下,它是:)
gcc
返回int __builtin_clz (unsigned int x)
中从0开始的前导0位数
重要的位置。如果X
为0,则结果未定义。(X
参数的__builtin_clzl
和unsigned long
的{{1}}也可用。)