欧拉#5项目;这个解决方案有效 - 但为什么

Project Euler # 5; this solution works - but why?

本文关键字:有效 为什么 解决方案 项目 欧拉      更新时间:2023-10-16

项目欧拉问题 5 表述为:"2520 是最小的数,可以除以 1 到 10 的每个数,没有任何余数。

被 1 到 20 的所有数字均匀整除的最小正数是多少?这是我正在使用的函数的 c++ 代码。

    long long unsigned int rangeLCM(int n)
    {
         long long unsigned int ans=1;
         for(int i=1;i<=n;i++)
         {
            if(ans%i!=0)
            {
              if(i%(ans%i)==0)ans*=(i/(ans%i));
              else ans*=i;
            }
         } 
         return ans;
    }

该代码适用于问题中所述的示例和问题本身{rangeLCM(10)=2520rangeLCM(20)=232792560},但我认为它并不完美,并且错过了一些边缘情况。

我没有实际计算LCM(ans,i),而是检查了两者中较大的一个(总是ans)可以被i整除。如果不是,则ans乘以等于 i/(ans%i)i 的数字,具体取决于i是否可以被 (ans%i) 整除。

这是基于以下事实:

LCM(8,12)=24=12*(8/(12%8));
LCM(9,30)=90=30*(9/(30%9)
LCM(7,13)=91=13*7

但是,对于以下类型的情况,它将失败:LCM(8,14)=56 != 8*14

然而,rangeLCM 的代码为我尝试过的所有输入提供了正确的输出。为什么?

你的逻辑不起作用

          if(i%(ans%i)==0)ans*=(i/(ans%i));
          else ans*=i;

例如,如果 ans = 10i = 14 ,则 lcm 应为 70,但在代码中为 140。

原因是,在 ansi 之间,存在公共除数,但您的代码无法检测到。

为了进行实验,我写了一小段代码来使用 Java 进行检查。

class Solution {
    public static void main(String[] args) {
        long ans = 1;
        for (long i = 1; i <= 40; i++) {
            if (ans % i != 0) {
                long before = (ans*i/gcd(ans,i));
                if (i % (ans % i) == 0){
                    ans *= (i / (ans % i));
                }else{
                    ans *= i;
                }
                System.out.println(ans + " " + before + " " + i);
            }
        }
    }
    public static long gcd(long a, long b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
}

输出

2 2 2
6 6 3
12 12 4
60 60 5
420 420 7
840 840 8
2520 2520 9
27720 27720 11
360360 360360 13
720720 720720 16
12252240 12252240 17
232792560 232792560 19
5354228880 5354228880 23
26771144400 26771144400 25
722820898800 80313433200 27
20961806065200 20961806065200 29
649815988021200 649815988021200 31
1299631976042400 1299631976042400 32
48086383113568800 48086383113568800 37

当 i = 27 时,正确答案和ans

lcm(a,b) 的公式为

lcm(a,b) = a*b/gcd(a,b)

与 gcd 是两个数字 a 和 b 之间的最大公约数

我认为您错过了很多情况,您必须在

if(i%(ans%i)==0)ans*=(i/(ans%i));