Project-Euler-005短除法

005题:

题意:

​ 2520是最小的能够被1到10整除的数。

​ 最小的能够被1到20整除的正数是多少?

思路:

​ 我们能够想到,既然是12的倍数,那么也一定会是1,2,3,4,6的倍数;既然是14的倍数,也一定会是7的倍数;既然是15的倍数,也一定是5的倍数;既然是16的倍数,也一定是8的倍数;既然是18的倍数,也一定是9的倍数;既然是20的倍数,那一定也是10的倍数

​ 所以,我们只需要考虑11~20的最小公倍数即可

​ 思路一:​ 利用辗转相除法求11和12的最大公因子,进而通过11*12/gcd(11,12) 来求它们的最小公倍数,然后求最小公倍数和13的最小公倍数并更新最小公倍数,循环上述过程直到20

​ 思路二:我们知道,两个数的最小公倍数,相比它俩相乘,缩小了它俩的公共因数倍。

​ 类比到多个数,比如: 2,3, 6, 12,16:

2 = 2; 3 = 3; 6 = 3*2; 12 = 3 * 2* 2;16 = 2 * 2 * 2 * 2;

​ 我们发现:

​ 公因子2在2中存在1次,在6中存在1次,在12中存在2次,在16中存在4次

​ 公因子3在3中存在1次,在6中存在1次,在12中存在1次

​ 那么它们的最小公倍数,就是pow(2,4)* pow(3,1)= 48

​ 也就是说,每个因子找这些数中它出现的最大次数,其它数都是重复的,可以去掉,然后累乘每个因子的最大次数幂即为最小公倍数。

​ 除了运算速度快之外,还可以避免辗转相除法取余1e9+7导致错误的尴尬(只有累乘不会出错,但是中途取余求gcd会造成错误)

​ 兴冲冲的发现了这个规律后,结果一百度发现已经存在这个定理了,叫短除法。。哎,优队算法就这样没了。。。

代码:

​ 和之前一样,暴力求法不写

#include <stdio.h>
#include <algorithm>
#include <inttypes.h>
#define ll int64_t
#define d int32_t
using namespace std;

d a[10];
ll ans = 1;         //最终结果
ll prime[8] = {2, 3, 5, 7, 11, 13, 17, 19};  //20以内的质数

//用于存储11~20
void init() {
    for (d i = 0; i < 10; i ++) {
        a[i] = 11 + i;
    }
}

//快速幂函数
ll quick (ll a, d b) {
    ll res = 1;
    while (b) {
        if (b & 1) res *= a;
        b >>= 1;
        a *= a;
    }
    return res;
}

//短除法
void short_division() {
    for (d i = 0; i < 8; i ++) {
        d maxx = 0;                 //对于11~20,能够循环整除prime[i]的最大次数
        for (d j = 0; j < 10; j++) {
            d inx = 0;              //记录当前数能循环整除prime[i]的最大次数
            while (a[j] % prime[i] == 0) {
                a[j] /= prime[i];
                inx ++;
            }
            maxx = max(maxx, inx);
        }
        ans *= quick(prime[i], maxx);   //结果乘质因子的最大循环整除次数次幂
    }
    printf("%" PRId64"\n", ans);    //最后结果为11~20,也就是1~20的最小公倍数
}

int main()
{
    init();
    short_division();
    return 0;
}

最后结果为:232792560

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值