• AcWing 197. 阶乘分解


    题目传送门

    一、排除错误作法

    错误作法I

    直接算出\(N\)的阶乘,数据范围\(1e6\),阶乘太大\(long \ \ long\)装不下,就开高精度,然后再考虑质因子分解,这么麻烦就等着挂吧,而且,高精度后,也不知道咋能进行质数因子分解,反正我是不会...

    错误作法II

    \(1~N\)中每一个数字都质因数分解,分别计算质因子个数,然后用桶计数,累加!
    这样做的算法复杂度是多少呢?
    \(O(N\sqrt{N})\),其中\(N=10^6\),那就是\(10^6 * 10^3=10^9\),这么干会\(TLE\)了!

    二、经典算法分析

    三、算法步骤

    1. 筛出\(1 \sim n\)的所有质数
    2. 枚举每个质因子\(x\)\(n!\)表示\(1 * 2 * 3... * n\),从\(1\)\(n\)中,求\(x\)的次数:

    \[cnt(x)= \left \lfloor \frac{n}{x^1} \right \rfloor + \left \lfloor \frac{n}{x^2} \right \rfloor + \left \lfloor \frac{n}{x^3} \right \rfloor + ... \]

    (直到\(x\)的次方大于\(n\)停止)

    四、时间复杂度 \(O(n)\)

    质数个数定理\(1 \sim n\)中有大约有 $ \frac{n}{ln(n)}$ 个质数。
    \(\frac{n}{ln(n)}\)个质数,每个质数求\(log_xn\)次,

    总的计算次数=$$ \frac{n}{ln(n)} * log_xn <= \frac{n}{log_2n} * log_2n =n$$
    使用数字\(2\)进行换底,将等式值扩大,最大是\(n\),因此时间复杂度是\(O(n)\)级别

    五、实现代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    //欧拉筛
    const int N = 1e6 + 10;
    int primes[N], cnt; // primes[]存储所有素数
    bool st[N];         // st[x]存储x是否被筛掉
    void get_primes(int n) {
        memset(st, 0, sizeof st);
        cnt = 0;
        for (int i = 2; i <= n; i++) {
            if (!st[i]) primes[cnt++] = i;
            for (int j = 0; primes[j] * i <= n; j++) {
                st[primes[j] * i] = true;
                if (i % primes[j] == 0) break;
            }
        }
    }
    int main() {
        int n;
        cin >> n;
        get_primes(n);
    
        for (int i = 0; i < cnt; i++) {
            int p = primes[i];
            int s = 0;
            // 方法1(yxc大佬思维):
            // 思路:由大到小+除法降维
            // 优点:不用考虑乘法而导致的爆int上限
            // 缺点:逆向思维,不好想
            for (int j = n; j; j /= p) s += j / p;
    
            // 方法2(普通人正常思维)
            // 思路:由小到大+累记乘方
            // 优点:正向思维
            // 缺点:因为存在极限的乘法,可能爆int,需要开LL变量
            // for (LL j = p; j <= n; j *= p) s += n / j;
    
            // 方法3(错误作法)
            // 因为最后 j*=primes[i]会造成j爆int,变成负数,导致s变小)
            // for (int j = p; j <= n; j *= p) s += n / j;
            printf("%d %d\n", p, s);
        }
        return 0;
    }
    
  • 相关阅读:
    An impassioned circulation of affection(尺取+预处理)
    旅游(CSUST省赛选拔赛2+状压dp+最短路)
    Islands and Bridges(POJ2288+状压dp+Hamilton 回路)
    Travelling(HDU3001+状压dp+三进制+最短路)
    Hie with the Pie(POJ3311+floyd+状压dp+TSP问题dp解法)
    hash(2018年CSUST省赛选拔赛第一场B题+hash+字典树)
    Everything Has Changed(HDU6354+圆交+求周长)
    [iOS Animation]-CALayer 图层几何学
    [iOS Animation]-CALayer 显示方式
    [iOS Animation]-CALayer 图层树
  • 原文地址:https://www.cnblogs.com/littlehb/p/16283654.html
Copyright © 2020-2023  润新知