有一个数字N 每次迭代等于(N * 2)-1 我需要找出数字将是原始N的倍数的多少步;
(1≤N≤2·10 9)
例如:
N = 7; count = 0
N_ = 7*2-1 = 13; count = 1; N_ % N != 0
N_ = 13*2-1 = 25; count = 2; N_ % N != 0
N_ = 25*2-1 = 49; count = 3; N_ % N == 0
答案是3
如果无法以这种方式分解,则输出-1
#include <iostream>
using namespace std;
int main(){
int N,M,c;
cin >> N;
if (N%2==0) {
cout << -1;
return 0;
}
M = N*2-1;
c = 1;
while (M%N!=0){
c+=1;
M=M*2-1;
}
cout << c;
return 0;
}
在(1秒限制)内不适合。如何优化算法?
P.S所有指示的答案都进行了优化,但是一秒钟之内无法解决,因为您原则上需要更改算法。解决方案是使用欧拉定理。
答案 0 :(得分:5)
正如其他答案所建议的,该问题等同于找到c
这样的pow(2, c) = 1 mod N
。如果N为偶数,那么这是不可能的,否则是不可能的(正如您的代码表明的那样)。
线性时间方法是:
int c = 1;
uint64_t m = 2;
while (m != 1){
c += 1;
m = (2*m)%N;
}
printf("%d\n", c);
要在1秒钟内解决这个问题,我认为您不能使用线性时间算法。最坏的情况是N
为素数且较大时。例如,上面的代码可以在我的笔记本电脑上运行约10秒的1999999817。
相反,将N
分解为其主要因子。为每个素数因子解2^c = 1 mod p^k
(其中p ^ k出现在N的素数因子分解中。然后使用中国剩余定理将结果合并。
找到给定主功率的c
时,如果k=1
,则解决方案为c=p-1
。当k
较大时,细节非常混乱,但是您可以在此处找到书面解决方案:https://math.stackexchange.com/questions/1863037/discrete-logarithm-modulo-powers-of-a-small-prime
答案 1 :(得分:4)
问题是您正在溢出,int数据类型仅具有32位,并且溢出2 ^ 31-1,在此问题中,您无需保留M的实际值,只需保留n的模。
while (M%N!=0){
c+=1;
M=M*2-1;
M%=N
}
编辑:此外,您实际上不需要超过N次迭代来检查是否存在0 mod,因为N中只有N个不同的mod,并且它不断循环。因此,如果没有0 mod,还需要牢记这一点。
答案 2 :(得分:2)
毫无疑问,您的代码的主要问题是有符号整数溢出
每当Return:
true : DB save successful
false : DB save unsuccessful
发生更改(即M
)时,我都会添加M
的打印件,并输入29。这就是我得到的:
cout << M << endl;
如您所见,您已经签名了整数溢出。这是C语言中的未定义行为,因此任何事情都可能发生!在我的机器上,我最终遇到了一个讨厌的无尽循环。在考虑性能之前,必须先解决该问题。
简单的解决方法是添加一行,如
57
113
225
449
897
1793
3585
7169
14337
28673
57345
114689
229377
458753
917505
1835009
3670017
7340033
14680065
29360129
58720257
117440513
234881025
469762049
939524097
1879048193
-536870911
-1073741823
-2147483647
1
1
1
1
... endless loop
更改M = M % N;
时。查看@Malek的答案
此外,您还应该使用 unsigned 整数,即对所有变量使用M
。
但是,这将不会提高性能。
如果在上述修复后仍然存在性能问题,则可以尝试以下方法:
uint32_t
在我的笔记本电脑上,对1..100000范围内的所有奇数进行测试时,该算法的速度提高了2.5倍。但是,对于范围为1..2 * 10 ^ 9的所有数字,可能还不够。
还要注意使用 uint32_t N;
cin >> N;
if (N%2==0) {
cout << -1;
return 0;
}
// Alternative algorithm
uint32_t R,c;
R = 1;
c = 1;
while (R != N){
R = 2*R + 1;
if (R > N) R = R - N;
++c;
}
cout << c;
以避免整数溢出。