Python 对于较大的输入,使此程序运行得更快时遇到问题

Python 对于较大的输入,使此程序运行得更快时遇到问题,python,performance,math,time-complexity,Python,Performance,Math,Time Complexity,该程序表示一个通用公式,其中x=(i*k+j)%m其中k是上一个答案的值。在某种意义上,它基本上是x1=(i*x0+j)%m,和x2=(i*x1+j)%m,等等。我遇到的问题是,计算大型输入需要很长时间 考虑到这一点,我一直在考虑使用算术级数公式,例如:a+(n-1)*d),但我不确定如何在这样的程序中实现它 def calculate(i,j,m,k,n): for v in range(1,n+1): ans = (i*k + j) % m k = a

该程序表示一个通用公式,其中
x=(i*k+j)%m
其中
k
是上一个答案的值。在某种意义上,它基本上是
x1=(i*x0+j)%m
,和
x2=(i*x1+j)%m
,等等。我遇到的问题是,计算大型输入需要很长时间

考虑到这一点,我一直在考虑使用算术级数公式,例如:
a+(n-1)*d)
,但我不确定如何在这样的程序中实现它

def calculate(i,j,m,k,n):
    for v in range(1,n+1):
        ans = (i*k + j) % m
        k = ans
    return ans
找到了最后一行

如果
m
是素数,则该公式很好。 在这种情况下,你可以用这个素数进行所有的计算, 包括分区,以保持数字较小。 你只需要快速地进行指数运算
i^n
。 我建议你看看里面的参考资料。 与循环的O(n)相比,这应该给您O(log(n))时间复杂度

如果
m
不是素数,则上述公式中的除法很烦人。但是你也可以通过平方来计算和,做一些类似于指数的事情。观察

x1 = (i * x0 + j)
x2 = (i * x1 + j) = i * i * x0 + i * j + j
x3 = i * i * i * x0 + i * i * j + i * j + j
xn = i^n * x0 + sum(i^t for t from 0 to n - 1) * j
   = i^n * x0 + (i^n - 1) / (i - 1) * j
因此,在每一步中,可以将右括号中的求和数减半。现在没有除法,所以可以在每次运算后执行模运算。 因此,您可以定义如下内容

1 + i + i^2 + i^3 + i^4 + i^5 + i^6 + … + i^(2n+1) =
(1 + i) * (1 + i^2 + i^4 + i^6 + … + i^n)
1 + i + i^2 + i^3 + i^4 + i^5 + i^6 + … + i^(2n+2) =
1 + (i + i^2) * (1 + i^2 + i^4 + i^6 + … + i^n)
在针对您的实现运行一些随机和一些不太随机的测试用例时,可以看到整个计算

找到了最后一行

如果
m
是素数,则该公式很好。 在这种情况下,你可以用这个素数进行所有的计算, 包括分区,以保持数字较小。 你只需要快速地进行指数运算
i^n
。 我建议你看看里面的参考资料。 与循环的O(n)相比,这应该给您O(log(n))时间复杂度

如果
m
不是素数,则上述公式中的除法很烦人。但是你也可以通过平方来计算和,做一些类似于指数的事情。观察

x1 = (i * x0 + j)
x2 = (i * x1 + j) = i * i * x0 + i * j + j
x3 = i * i * i * x0 + i * i * j + i * j + j
xn = i^n * x0 + sum(i^t for t from 0 to n - 1) * j
   = i^n * x0 + (i^n - 1) / (i - 1) * j
因此,在每一步中,可以将右括号中的求和数减半。现在没有除法,所以可以在每次运算后执行模运算。 因此,您可以定义如下内容

1 + i + i^2 + i^3 + i^4 + i^5 + i^6 + … + i^(2n+1) =
(1 + i) * (1 + i^2 + i^4 + i^6 + … + i^n)
1 + i + i^2 + i^3 + i^4 + i^5 + i^6 + … + i^(2n+2) =
1 + (i + i^2) * (1 + i^2 + i^4 + i^6 + … + i^n)


在针对您的实现运行一些随机和一些不太随机的测试用例时,可以看到整个计算。

您能纠正示例代码中的缩进吗?Python非常依赖缩进,很难说这段代码是什么意思。Python编译器可能也会抱怨缩进不一致。将两个循环行重写为
k=(i*k+j)%m
,这将为您节省一条赋值语句。大到什么程度?@DYZ-Like n=100000000看起来这对Python来说是一个不公平的任务。C语言中的同一个程序需要2秒钟。为了澄清上述问题:例如,i=3,j=5,m=10,k=1,n=3,然后(i*k+j)%m=(3*(1)+5)%10=8(第一次迭代),(3*(8)+5)%10=9(第二次迭代),(3*(9)+5)%10=2(第三次迭代)然后程序将输出2作为其结果。您能纠正示例代码中的缩进吗?Python非常依赖缩进,很难说这段代码是什么意思。Python编译器可能也会抱怨缩进不一致。将两个循环行重写为
k=(i*k+j)%m
,这将为您节省一条赋值语句。大到什么程度?@DYZ-Like n=100000000看起来这对Python来说是一个不公平的任务。C语言中的同一个程序需要2秒钟。为了澄清上述问题:例如,i=3,j=5,m=10,k=1,n=3,然后(i*k+j)%m=(3*(1)+5)%10=8(第一次迭代),(3*(8)+5)%10=9(第二次迭代),(3*(9)+5)%10=2(第三次迭代)然后程序将输出2作为结果。我不确定我的解释是否不清楚,或者是否误解了你的答案。我意识到这代表I^n,我想要I*k,即上一个术语。kth值的功率不会随着每次迭代而增加。更像这样:假设i=3,k=1,j=5和m=10,然后(i*k+j)%m=(3*(1)+5)%10=8,基于for循环的下一次迭代将是(3*(8)+5)%10=9。使用上面的程序,虽然更快会给我错误的答案output@Zaruya,您能否为所有
(i,j,m,k,n)
提供特定的值,如果您认为第一个框中的公式不能正确工作,请将其翻译为Python
(i**n*k+(i**n-1)/(i-1)*j)%m
@SergGr似乎我没有正确地执行程序。用这个公式,你刚才给了我答案。然而,这仍然需要一段时间的更大values@SergGr只是modpowsum函数似乎不起作用,我不确定我的解释是否不清楚,或者误解了你的答案。我意识到这代表I^n,我想要I*k,即上一个术语。kth值的功率不会随着每次迭代而增加。更像这样:假设i=3,k=1,j=5和m=10,然后(i*k+j)%m=(3*(1)+5)%10=8,基于for循环的下一次迭代将是(3*(8)+5)%10=9。使用上面的程序,虽然更快会给我错误的答案output@Zaruya,您能否为所有
(i,j,m,k,n)
提供特定的值,如果您认为第一个框中的公式不能正确工作,请将其翻译为Python
(i**n*k+(i**n-1)/(i-1)*j)%m
@SergGr似乎我没有正确地执行程序。用这个公式,你刚才给了我答案。然而,这仍然需要一段时间的更大values@SergGr只是modpowsum函数似乎不起作用