项目欧拉号160 - 尝试C

时间:2014-05-15 18:02:19

标签: c math numbers number-theory

请原谅我,如果我有点傻,但我最近才开始编程,而且我可能有点超出了我对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);
}

5 个答案:

答案 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 > 1f(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;
 }
  • 不要忘记变量f必须足够大才能基础^ 2
  • 且基数必须至少比2位大2位才能覆盖5位数并溢出为零
  • base必须是10的幂才能保留十进制数字

[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
  • 越接近b,有效数字越少越好!!!
  • 这就是f(1001000)不起作用的原因......

答案 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。