• 质数有关知识总结加复习


    一、基本的思想和定理。

    算数基本定理,也叫唯一分解定理。指的是一个大于一的合数都可以分解为有限个质数相乘。即N=p1a1p2a2*.....*pnan。p即为质数,a为质数的指数。

    二、一些重要的公式。

    1、求约数个数和约数的和。

     给定一正整数n,求n的所有约数的个数。公式:num=(a1+1)*(a2+1)*......*(an+1)。至于原理,我理解的思路是,按照组合原则,p1a1一共有(a1+1)种情况,其余的以此类推。

    2、求约数个数的和。

    给定一个正整数n,求n的所有约数之和。公式:sum=(1+p11+p12+.....+p1n)*(1+p21+p22+.....+p2n)*......*(1+pn1+pn2+...+pnn)。原理就是,把n的约数和分解为pa的约数和。

    3、欧拉函数。

    φ(n)表示为某一个正整数的欧拉函数:小于n的正整数中和n互质的正整数的个数。

    欧拉函数具有以下三个特性:

    // 1、φ(n)=n*(1-1/p1)*(1-1/p)*(1-1/p3)*.....*(1-1/pn);

    // 2、若m为质数,n%m==0,则φ(m*n)=m*φ(n);

    // 3、若m,n互质,则φ(n*m)=φ(m)*φ(n)。

    三、C++代码。

    1、如何判断素数。

    // 常规的方法是判断n是否能被2到n之间的数整除,如果能够整除,则说明n有除了1以外的其他因数,则n不是质数。 

    优化后的思路是:假如存在一个数(不一定为正整数)i,使得i*i=n,则我们可以从2到i之间的数进行判断,因为两个数之间成反比关系,一个肯定大于等于i,另一个肯定小于等于i。那么,只要保证在2到i之间没有正整数可以整除n,我们就可以知道,n一定为质数。

    bool is_prime(int n)
    {
        for (int i = 2; i * i <= n;i++){
            if(n%i==0){
                return false;
            }
        }
        return true;
    }

    2、如何分解质因数。

    // 分解质因数首先从最小的质数开始分解,如果能够被整除,则一直循环到不能被整除为止,在此期间还可以计算质因数出现的次数。

    同样也可以进行优化,和如何判断质数的优化方法一样,如果有这样的数i,我们就可以在<=i处提前判断完成,因为在判断前面的质数之后,大于i的部分不可能会有质数再被整除。

    除非当我们整除这些质数之后的n,本身就是一个比较大的质数,这时候,我们可以在最后判断n是否大于1,是的话,n即为质数。比如1004=2^2*251。在我们枚举2之后,n的值就变成了251,这时候从3到sqrt(251,1/2)之间都没有数整除n。

    vector<pair<int,int>> v;
    int Prime_factorization(int n)
    {
        for (int i = 2; i * i < n;i++){
            if(n%i==0){
                int s = 0;
                while(n%i==0){
                    n /= i;
                    s++;
                    v.push_back({i, s});
                }
            }
        }
        if(n>1){
            v.push_back({n, 1});
        }
    }

    // 如果对动态数组不熟悉,可以尝试用结构来构建。

    3、筛选素数之埃式筛选法(E_sieve)

    // 埃式筛选的原理也很简单,在我们找到一个素数之后,素数的倍数一定不是素数。根据这一原则,我们就可以进行筛选了。

    优化的地方和上面一样,首先是找素数的过程,到i处就可以了。然后是在素数的倍数方面,当i=5时,2*5,3*5,4*5已经在前面优化过了。这时候从5*5开始筛选就可以了。

    时间复杂度O(nloglogn)

    int primes[maxx];
    bool vis[maxx];
    void E_sieve(int n)
    {
        memset(vis, 0, sizeof(vis));
        int k = 0;
        for (int i = 2; i * i <= n;i++){
            if(!vis[i]){
                primes[k++] = i;
                for (int j = i * i; j <= n;j += i){
                    vis[primes[j] * i] = true;
                }
            }
        }
    }

    4、筛选素数之线性筛(Linear_sieve)

    // 线性筛主要是针对埃筛的一些问题进行解决,以使得时间复杂度降低。埃筛的主要问题是一个数可以被两个质数筛选。即使是优化后的代码。比如12被2和3两个质数筛选。

    优化方面会有一些难懂。推荐先记忆模板,再慢慢理解。

    优化的地方在:我们在筛选的时候,让合数被最小质因数筛选。加一个判定条件就可以了。

    时间复杂度O(n)

    int primes[maxx];
    bool vis[maxx];
    void Linear_sieve(int n)
    {
        int k = 0;
        for (int i = 2; i * i <= n;i++){
            if(!vis[maxx]){
                primes[k++] = i;
            }
            for (int j = 0; primes[j] * i <= n;j++){
                vis[primes[j] * i] = true;
                if(i%primes[j]==0){
                    break;
                }
            }
        }
    }

    对于第二个for循环里的if语句,就是说,如果i可以整除primes[j],那么primes[j+1]一定不是primes[j+1】*i的最小质因数。比如i=2,primes[0]=2;2%2=0,下一个质数为3,而2*3的最小质因数为2,因此break;

    // 可以自己手动列式子理解一下。

    5、筛选素数之欧拉筛。//放到后面去讲

    6、求所有约数

    // 和找质因数一样的道理。

    vector<int> v;
    void Divisor_find(int n)
    {
        for (int i = 1; i * i <= n;i++){
            if(n%i==0){
                v.push_back(i);
                if(i!=n/i){
                    v.push_back(n / i);
                }
            }
        }
    }

    7、求所有约数的个数。

    // 根据公式求就可以了。分解质因数记录质数的指数。

    int cnt[maxx];
    int k = 0;
    int Number_of_divisor(int n)
    {
        for (int i = 2; i * i <= n;i++){
            if(n%i==0){
                int s = 0;
                while(n%i==0){
                    n /= i;
                    s++;
                }
                cnt[k++] = s;
            }
        }
        int sum = 0;
        for (int i = 0; i < k;i++){
            sum += (cnt[i] + 1);
        }
        return sum;
    }

    8、求所有约数的和。

    // 一样的道理,根据公式求即可。不过要注意的是,可能会用到费马小定理。但是这里我们还是要注意一个公式就是x/y%mod可以转换为x%(y*mod)/y;

    ll quickpow(ll a,ll b)
    {
        ll res = 1;
        while(b){
            if(b&1){
                res = (res * a);
            }
            b >>= 1;
            a = (a * a);
        }
        return res;
    }
    
    int a[maxx], b[maxx];
    int k = 0;
    int Sum_of_divisor(int n)
    {
        for (int i = 2; i * i <= n;i++){
            if(n%i==0){
                int s = 0;
                while(n%i==0){
                    n /= i;
                    s++;
                }
                a[k] = i;
                b[k] = s;
                k++;
            }
        }
        if(n>1){
            a[k] = n;
            b[k] = 1;
            k++;
        }
        int sum;
        for (int i = 0; i < k;i++){
            sum += (quickpow(a[i], b[i] + 1) - 1) / (1 - a[i]);
        }
    
        return sum;
    }

    9、欧拉函数

    // n*(i-1/p)可以换成n/p*(p-1)。然后按公式写就可以了。

    int Euler_function(int n)
    {
        int res = n;
        for (int i = 2; i * i <= n;i++){
            if(n%i==0){
                res = res / i * (i - 1);
                while(n%i==0){
                    n /= i;
                }
            }
        }
        if(n>1){
            res = res / n * (n - 1);
        }
        return res;
    }

    10、欧拉筛

    // 根据欧拉函数三个特性写

    int primes[maxx], phi[maxx];
    bool vis[maxx];
    void Euler_sieve()
    {
        memset(vis, 0, sizeof(vis));
        int cnt = 0;
        for (int i = 2; i * i <= n;i++){
            if(!vis[i]){
                primes[cnt++] = i;
                phi[i] = i - 1;
            }
            for (int j = 0; primes[j] * i <= n;j++){
                vis[primes[j] * i] = true;
                if(i%primes[j]==0){
                    phi[primes[j] * i] = primes[j] * phi[i];
                    break;
                }
                else{
                    phi[primes[j] * i] = phi[i] * (primes[j] - 1);
                }
            }
        }
    }
  • 相关阅读:
    一款你不容错过的Laravel后台管理扩展包 —— Voyager
    关于后台动态模板添加内容的总结 Builder使用
    Python 解决 :NameError: name 'reload' is not defined 问题
    thinkcmf,thinksns,thinkphp,onethink三者是什么关系?
    PHP中用下划线开头的变量含义
    NetBeans 时事通讯(刊号 # 77 Oct 21, 2009)
    NetBeans 时事通讯(刊号 # 78 Oct 27, 2009)
    最受欢迎的中国 50 技术博客评选结果
    祝父亲生日快乐
    最受欢迎的中国 50 技术博客评选结果
  • 原文地址:https://www.cnblogs.com/Drqidian/p/13398484.html
Copyright © 2020-2023  润新知