欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 数据结构与算法-数学-基础数学算法(筛质数,最大公约数,最小公倍数,质因数算法,快速幂,乘法逆元,欧拉函数)

数据结构与算法-数学-基础数学算法(筛质数,最大公约数,最小公倍数,质因数算法,快速幂,乘法逆元,欧拉函数)

2025/4/12 22:35:33 来源:https://blog.csdn.net/2401_84910613/article/details/147051688  浏览:    关键词:数据结构与算法-数学-基础数学算法(筛质数,最大公约数,最小公倍数,质因数算法,快速幂,乘法逆元,欧拉函数)

一:筛质数:

1-埃氏筛法

该算法核心是从 2 开始,把每个质数的倍数标记为合数,时间复杂度约为 O(nloglogn)。

#include <iostream>

#include <vector>u

sing namespace std;

const int N = 1000010;

bool st[N];  // 标记数组,true表示是合数,false表示是质数

void get_primes(int n) {

    for (int i = 2; i <= n; i++) {

        if (!st[i]) {

            for (int j = i + i; j <= n; j += i) {

                st[j] = true;

            }

        }

    }}

int main() {

    int n;

    cin >> n;

    get_primes(n);

    for (int i = 2; i <= n; i++) {

        if (!st[i]) cout << i << ' ';

    }

    return 0;}

2-线性筛法:

在埃氏筛法的基础上进行进一步的优化,保证所有的合数都是被最小的质因子筛掉

#include <iostream>

#include <vector>

using namespace std;

const int N = 1000010;

int primes[N], cnt;  // primes数组存储质数,cnt记录质数个数

bool st[N];  // 标记数组,true表示是合数,false表示是质数

void get_primes(int n) {

    for (int i = 2; i <= n; i++) {

        if (!st[i]) primes[cnt++] = i;

        for (int j = 0; primes[j] <= n / i; 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++) {

        cout << primes[i] << ' ';

    }

return 0;

}

二:最大公约数和最小公倍数

最小公约数:

是扩展欧几里得的基础版本,可以求出a和b的最小公约数

int gcd(int a, int b) {

return b ? gcd(b, a % b) : a;

}

int main() {

    int a, b;

    cin >> a >> b;

    cout << gcd(a, b) << endl;

return 0;

}

最小公倍数:

int lcm(int a, int b) {

return a*b/gcd(a,  b);

}

三:质因数:分解质因数,质因数的和,质因数个数

分解质因数:

一个很暴力的做法,最后得到n的所有质因数

#include <iostream>

using namespace std;

void divide(int x) {

    for (int i = 2; i <= x / i; i++) {

        if (x % i == 0) {

            int s = 0;

            while (x % i == 0) {

                x /= i;

                s++;

            }

            cout << i << ' ' << s << endl;

        }

    }

if (x > 1) cout << x << ' ' << 1 << endl;

}

int main() {

    int n;

    cin >> n;

    divide(n);

return 0;

}

约数的个数

若 N=p1^a1*p2^a2*⋯pk^ak​​,则 N 的约数个数为 (a1+1)(a2+1)⋯(ak+1)。

#include <iostream>

using namespace std;

int numofdividors(int x) {

    int res=1;

    for (int i = 2; i <= x / i; i++) {

        if (x % i == 0) {

            int s = 0;

            while (x % i == 0) {

                x /= i;

                s++;

            }

            cout << i << ' ' << s << endl;

            res=res*(s+1);

        }

    }

if (x > 1){

     cout << x << ' ' << 1 << endl;

     res*=2;

}

return res;

}

int main() {

    int n;

    cin >> n;

    cout<<divide(n);

return 0;

}

约数的和

N=p1^a1*p2^a2⋯pk^ak则 N 的

约数和为 (p1^0+p1^1+⋯+p1^a1)(p2^0+p2^1+⋯+p2^a2)⋯(pk^0+pk^1++pk^ak)。

int main() {

    int n;

    cin >> n;

    unordered_map<int, int> primes;

    while (n--) {

        int x;

        cin >> x;

        for (int i = 2; i <= x / i; i++) {

            while (x % i == 0) {

                x /= i;

                primes[i]++;

            }

        }

        if (x > 1) primes[x]++;

    }

    LL res = 1;

    for (auto p : primes) {

        LL a = p.first, b = p.second;

        LL t = 1;

        while (b--) t = (t * a + 1) % mod;

        res = res * t % mod;

    }

    cout << res << endl;

return 0;

}

四:快速幂和乘法逆元

快速幂可以在logn级别的时间里确定n^b mod p

#include <iostream>

using namespace std;

typedef long long LL;

快速幂:

LL qmi(int a, int k, int p) {

    LL res = 1;

    while (k) {

        if (k & 1) res = res * a % p;

        a = (LL)a * a % p;

        k >>= 1;

    }

return res;

}

int main() {

    int a, k, p;

    cin >> a >> k >> p;

    cout << qmi(a, k, p) << endl;

return 0;

}

乘法逆元:

在mod p的环境下 a^-1 = a^ (p-2)

#include <iostream>

using namespace std;

typedef long long LL;

LL qmi(int a, int k, int p) {

    LL res = 1;

    while (k) {

        if (k & 1) res = res * a % p;

        a = (LL)a * a % p;

        k >>= 1;

    }

return res;

}

int main() {

    int a, p;

    cin >> a >> p;

    if (a % p == 0) cout << "impossible" << endl;

    else cout << qmi(a, p - 2, p) << endl;

return 0;

}

五:欧拉函数

欧拉函数 φ(n) 表示小于等于 n 且与 n 互质的正整数的个数。若 n=p1^a1*p2^a2*⋯pk^ak​,

则 φ(n)=n(1−1/p1)(1−1/p2)⋯(1−1/pk)。

欧拉函数模版:

求出某一个数的欧拉函数值

#include <iostream>using namespace std;

int phi(int x) {

    int res = x;

    for (int i = 2; i <= x / i; i++) {

        if (x % i == 0) {

            res = res / i * (i - 1);

            while (x % i == 0) x /= i;

        }

    }

    if (x > 1) res = res / x * (x - 1);

    return res;}

int main() {

    int n;

    cin >> n;

    cout << phi(n) << endl;

return 0;

}

线性筛法求出1~n的欧拉函数:

只有一点点的改变

#include <iostream>

#include <vector>

using namespace std;

const int N = 1000010;

int primes[N], cnt;  // primes数组存储质数,cnt记录质数个数

bool st[N];  // 标记数组,true表示是合数,false表示是质数

void get_primes(int n) {

    for (int i = 2; i <= n; i++) {

        if (!st[i]) {

             primes[cnt++] = i;

             phi[cnt-1]=i-1;

}

        for (int j = 0; primes[j] <= n / i; j++) {

            st[primes[j] * i] = true;

            if (i % primes[j] == 0) {

                  phi[i*prime[j]]=phi[i]*prime[j];

                  break;

}

            phi[i*prime[j]]=phi[i]*(prime[j]-1);

        }

}

}

int main() {

    int n;

    cin >> n;

    get_primes(n);

    for (int i = 0; i < cnt; i++) {

        cout << primes[i] << ' ';

    }

return 0;

}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词