请原谅我,如果我有点傻,但我最近才开始编程,而且我可能有点超出了我对Euler项目的问题160的深度。我已经尝试过解决它,但似乎在任何个人计算机上通过1tn数字会花费太长时间,所以我想我应该研究数学以找到一些捷径。
项目欧拉问题160:
对于任何N,让f(N)为尾随零之前的最后五位数 旅店!。例如,
9! = 362880所以f(9)= 36288 10! = 3628800所以f(10)= 36288 20! = 2432902008176640000所以f(20)= 17664
查找f(1,000,000,000,000)
新尝试:
#include <stdio.h>
main()
{
//I have used long long ints everywhere to avoid possible multiplication errors
long long f; //f is f(1,000,000,000,000)
f = 1;
for (long long i = 1; i <= 1000000000000; i = ++i){
long long p;
for (p = i; (p % 10) == 0; p = p / 10) //p is i without proceeding zeros
;
p = (p % 1000000); //p is last six nontrivial digits of i
for (f = f * p; (f % 10) == 0; f = f / 10)
;
f = (f % 1000000);
}
f = (f % 100000);
printf("f(1,000,000,000,000) = %d\n", f);
}
旧尝试:
#include <stdio.h>
main()
{
//This part of the programme removes the zeros in factorials by dividing by 10 for each factor of 5, and finds f(1,000,000,000,000) inductively
long long int f, m; //f is f(n), m is 10^k for each multiple of 5
short k; //Stores multiplicity of 5 for each multiple of 5
f = 1;
for (long long i = 1; i <= 100000000000; ++i){
if ((i % 5) == 0){
k = 1;
for ((m = i / 5); (m % 5) == 0; m = m / 5) //Computes multiplicity of 5 in factorisation of i
++k;
m = 1;
for (short j = 1; j <= k; ++j) //Computes 10^k
m = 10 * m;
f = (((f * i) / m) % 100000);
}
else f = ((f * i) % 100000);
}
printf("f(1,000,000,000,000) = %d\n", f);
}
答案 0 :(得分:1)
问题是:
对于任何
N
,请f(N)
为N!
中尾随零之前的最后五位数。查找f(1,000,000,000,000)
让我们重新解释一下这个问题:
对于任何
N
,请g(N)
为N
中尾随零之前的最后五位数。对于任何N
,请f(N)
为g(N!)
。查找f(1,000,000,000,000)
。
现在,在编写代码之前,以数学方式证明这个断言:
N > 1
,f(N)
等于g(f(N-1) * g(N))
请注意,我自己没有证明这一点;我可能在这里犯了一个错误。 (更新:这似乎是错误的!我们必须更多地考虑这一点。)证明您满意。您可能希望首先证明一些中间结果,例如:
g(x * y) = g(g(x) * g(y))
等等。
一旦你获得了这个结果的证明,现在你有了一个可以用来找到任何f(N)
的递归关系,你必须处理的数字不会比N
。
答案 1 :(得分:1)
Prod(n->k)(k*a+c) mod a <=> c^k mod a
例如
prod[ 3, 1000003, 2000003,... , 999999000003 ] mod 1000000
等于
3^(1,000,000,000,000/1,000,000) mod 1000000
N中的尾随0的数量!等于N的因式分解数为5!
答案 2 :(得分:0)
我会计算整个事物然后将第一个非零数字与LSB分开...... 但对你来说,我认为这更好:
1.使用更大的基数
如1234560004587786542可以重写为基础 b = 1000 000 000 ,如下所示:
1*b^2 + 234560004*b^1 + 587786542*b^0
2.当你乘以时,低位数只取决于乘数的最低位数
A*B = (a0*b^0+a1*b^1+...)*(b0*b^0+b1*b^1+...)
= (a0*b0*b^0)+ (...*b^1) + (...*b^2)+ ...
3.一起输出
for (f=1,i=1;i<=N;i++)
{
j=i%base;
// here remove ending zeroes from j
f*=j;
// here remove ending zeroes from f
f%=base;
}
[edit1]实施
uint<2> f,i,j,n,base; // mine 64bit unsigned ints (i use 32bit compiler/app)
base="10000000000"; // base >= 100000^2 ... must be as string to avoid 32bit trunc
n="20"; // f(n) ... must be as string to avoid 32bit trunc
for (f=1,i=1;i<=n;i++)
{
j=i%base;
for (;(j)&&((j%10).iszero());j/=10);
f*=j;
for (;(f)&&((f%10).iszero());f/=10);
f%=base;
}
f%=100000;
int s=f.a[1]; // export low 32bit part of 64bit uint (s is the result)
太慢了:(
f(1000000)=12544 [17769.414 ms]
f( 20)=17664 [ 0.122 ms]
f( 10)=36288 [ 0.045 ms]
提高速度或使用任何快速因子实现
[edit2]只有几个32位n!用于测试的因子
此声明无效:(
//You could attempt to exploit that
//f(n) = ( f(n%base) * (f(base)^floor(n/base)) )%base
//do not forget that this is true only if base fulfill the conditions above
幸运的是,这个似乎是真的:)但只有当(a比b大得多,%base = 0)时
g((a+b)!)=g(g(a!)*g(b!))
// g mod base without last zeroes...
// this can speed up things a lot
f( 1)=00001
f( 10)=36288
f( 100)=16864
f( 1,000)=53472
f( 10,000)=79008
f( 100,000)=56096
f( 1,000,000)=12544
f( 10,000,000)=28125
f( 1,000,100)=42016
f( 1,000,100)=g(??????12544*??????16864)=g(??????42016)->42016
答案 3 :(得分:0)
我不是Euler求解器的专家项目,而是针对所有欧拉问题的一般建议。
1 - 首先以最明显的方式解决问题。这可能会为以后的尝试提供见解
2 - 针对较小范围解决问题。 Euler通常会给出可用于检查算法的较小范围的答案
3 - 扩大问题并找出问题如何在时间上随着问题变大而扩展
4 - 如果解决方案需要花费的时间超过几分钟,那么现在是时候检查算法并提出更好的方法了
5 - 请记住欧拉问题总是有答案,依赖于聪明的编程和聪明的数学相结合
6 - 许多人已经解决的问题不能错,你错了!
我最近解决了数字号码问题(欧拉的网站已经关闭,无法查找数字,这在发布时已经很近了)正是使用这些步骤。我最初的蛮力算法需要花费60个小时,我看一下解决了1,000,000个模式的模式,并找到了解决方案,找到了1.25秒的解决方案。
答案 4 :(得分:0)
分别处理结束2,4,5,6,8,0的数字可能是一个想法。结尾为1,3,7,9的数字无法导致尾随零。让
A(n) = 1 * 3 * 7 * 9 * 11 * 13 * 17 * 19 * ... * (n-1).
B(n) = 2 * 4 * 5 * 6 * 8 * 10 * 12 * 14 * 15 * 16 * 18 * 20 * ... * n.
n的阶乘是A(n)* B(n)。我们可以很容易地找到A(n)的最后五位数。首先找到A(100,000)MOD 100,000,我们可以通过简单地进行乘法修改100,000来实现这一点。请注意,A(200,000)MOD 100,000仅为A(100,000)* A(100,000)MOD 100,000为100,001 = 1 MOD 100,000等。因此A(1,000,000,000,000)仅为A(100,000)^ 10,000,000 MOD 100,000。
需要更多关注2,4,5,6,8,0您需要跟踪这些添加尾随零的时间。显然,每当我们乘以结束2或5的数字时,我们最终会得到零。但是,有些情况下你可以得到两个零25 * 4 = 100。