慢吞云雾缓吐愁 发表于 2025-4-8 18:00:40

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

一:筛质数:

1-埃氏筛法

该算法核心是从 2 开始,把每个质数的倍数标志为合数,时间复杂度约为 O(nloglogn)。
#include <iostream>
#include <vector>u
sing namespace std;
const int N = 1000010;
bool st;  // 标志数组,true表现是合数,false表现是质数
void get_primes(int n) {
    for (int i = 2; i <= n; i++) {
        if (!st) {
            for (int j = i + i; j <= n; j += i) {
                st = true;
            }
        }
    }}
int main() {
    int n;
    cin >> n;
    get_primes(n);
    for (int i = 2; i <= n; i++) {
        if (!st) cout << i << ' ';
    }
    return 0;}
2-线性筛法:

在埃氏筛法的基础上进行进一步的优化,包管全部的合数都是被最小的质因子筛掉
#include <iostream>
#include <vector>
using namespace std;
const int N = 1000010;
int primes, cnt;  // primes数组存储质数,cnt记录质数个数
bool st;  // 标志数组,true表现是合数,false表现是质数
void get_primes(int n) {
    for (int i = 2; i <= n; i++) {
        if (!st) primes = i;
        for (int j = 0; primes <= n / i; j++) {
            st * i] = true;
            if (i % primes == 0) break;
        }
}
}
int main() {
    int n;
    cin >> n;
    get_primes(n);
    for (int i = 0; i < cnt; i++) {
        cout << primes << ' ';
    }
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++;
            }
        }
        if (x > 1) primes++;
    }
    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, cnt;  // primes数组存储质数,cnt记录质数个数
bool st;  // 标志数组,true表现是合数,false表现是质数
void get_primes(int n) {
    for (int i = 2; i <= n; i++) {
        if (!st) {
             primes = i;
             phi=i-1;
}
        for (int j = 0; primes <= n / i; j++) {
            st * i] = true;
            if (i % primes == 0) {
                  phi]=phi*prime;
                  break;
}
            phi]=phi*(prime-1);
        }
}
}
int main() {
    int n;
    cin >> n;
    get_primes(n);
    for (int i = 0; i < cnt; i++) {
        cout << primes << ' ';
    }
return 0;
}



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 数据结构与算法-数学-基础数学算法(筛质数,最大公约数,最小公倍数,质因数算法,快速幂,乘法逆元,欧拉函数)