任务上的迭代次数

时间:2019-08-29 05:13:09

标签: c++ algorithm

有一个数字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所有指示的答案都进行了优化,但是一秒钟之内无法解决,因为您原则上需要更改算法。解决方案是使用欧拉定理。

3 个答案:

答案 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; 以避免整数溢出。