试除法判定质数 1 2 3 4 5 6 7 8 9 10 11 12 int n;int a;bool pr (int a) { if (a < 2 ) return false ; for (int i = 2 ; i <= a/i; i ++) { if (a % i == 0 ) return false ; } return true ; }
分解质因数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int n;void divide (int n) { for (int i = 2 ; i <= n/i; i ++) if (n % i == 0 ) { int s =0 ; while (n % i == 0 ) { n /= i; s ++; } cout << i << " " << s << endl; } if (n > 1 ) printf ("%d %d\n" ,n,1 ); cout << endl; }
埃氏筛法 筛法例子展示 思路 : 从小到大利用质数将质数的合数筛除(进行标记) 时间复杂度$O(nlog(logn))$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const int N =1000010 ;int st[N],primes[N]; int n,cnt;void get_primes (int n) { for (int i = 2 ; i <= n; i ++) { if (!st[i]) { primes[cnt ++] = i; for (int j = i; j <=n; j += i) st[j] = 1 ; } } }
线性筛法 埃氏筛法中一个合数会被不同的质因子筛多次,线性筛保证每个数只被其最小质因数筛去,如何实现呢?令循环在i %primes[j] == 0时退出步骤 :之前每筛到一个素数,便将这个素数放入到primes[ ]中,在每次循环中,从头开始遍历primes[ ], 筛选出的合数为 primes[j]×i那么如何保证每个数都只被筛选一次?即循环应该在何时结束? 筛质数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int n;void divide (int n) { for (int i = 2 ; i <= n/i; i ++) if (n % i == 0 ) { int s =0 ; while (n % i == 0 ) { n /= i; s ++; } cout << i << " " << s << endl; } if (n > 1 ) printf ("%d %d\n" ,n,1 ); cout << endl; }
试除法求约数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 vector<int > get_divisors (int n) { vector<int > res; for (int i = 1 ; i <= n/i; i ++) { if (n % i == 0 ) { res.push_back (i); if (i != n/i) res.push_back (n/i); } } sort (res.begin (),res.end ()); return res; } int main () { int n; cin >> n; while (n -- ) { int a; cin >> a; vector<int > res = get_divisors (a); for (auto t : res) { cout << t << " " ; } cout <<endl; } return 0 ; }
约数个数 约数个数定理 : 若 $n=\prod_{i=1}^{s} p_{i}{ }^{\alpha_{i}}$ , 则 $d(n)=\prod_{i=1}^{s}\left(\alpha_{i}+1\right)$ 。 一个数的约数是由其质因数分解中质因数的所有取法排列组合出来的证明 : $p_{i}{ }^{\alpha_{i}}$ 的约数有 $p_{i}^{0}, p_{i}^{1}, \cdots, p_{i}^{\alpha_{i}}$ 共 $\left(\alpha_{i}+1\right)$ 个, 根据乘法原理, $d(n)=\prod_{i=1}^{s}\left(\alpha_{i}+1\right)$ 。unordered_map中存储质因子及其指数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> #include <unordered_map> using namespace std;const int mod = 1e9 + 7 ;typedef long long LL;int main () { int n; cin >> n; unordered_map<int ,int > primes; while (n --) { int a; cin >> a; for (int i = 2 ; i <= a/i; i ++) { while (a % i == 0 ) { a /= i; primes[i] ++; } } if (a > 1 ) primes[a] ++ ; } LL res = 1 ; for (auto p : primes) res = res * (p.second + 1 )% mod; cout << res <<endl; return 0 ; }
约数之和 若 $n=\prod_{i=1}^{s} p_{i}{ }^{\alpha_{i}}$ , 则 $d(n)=\prod_{i=1}^{s}\left(\alpha_{i}+1\right)$ 。 约数本就是由其质因数分解中质因数的所有取法(即约数)排列组合出来的 故其和便是 这些排列组合的相加证明 : $p_{i}{ }^{\alpha_{i}}$ 的约数有 $p_{i}^{0}, p_{i}^{1}, \cdots, p_{i}^{\alpha_{i}}$ 共 $ \left(\alpha_{i}+1\right)$ 个, 其约数和为:$\sum_{j =0} ^{\alpha i}p_i$ 根据乘法原理, $f(n)=\prod {i=1}^{s}\sum_{j =0} ^{\alpha _i}p_i^j$
其各个质因数的幂次的约数和(t = (t * a + 1) )的乘积(展开之后) 等于 一个数的约数和 $f(n)= (p_1 ^0 +p_1^1 +p_1^2 \cdots+p_1^{\alpha_1})\times (p_2 ^0 +p_2^1 +p_2^2 \cdots+p_2^{\alpha_2})\times \cdots (p_i ^0 +p_i^1 +p_i^2 \cdots+p_i^{\alpha_i})$例: $12 = 2^2 \times 3 ^ 1$ $f(n)=(1 + 2 + 4) \times ( 1 +3) = 7 \times 4 = 28$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <unordered_map> using namespace std;const int mod = 1e9 +7 ;typedef long long LL;int main () { int n; cin >> n; unordered_map<int , int > prime; while (n --) { int x; cin >> x; for (int i =2 ; i <= x/i; i ++) { while (x % i ==0 ) { prime[i] ++; x /= i; } } if (x > 1 ) prime[x]++; } LL res = 1 ; for (auto p: prime) { 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 ; }
最大公约数 1 2 3 4 5 int gcd (int a, int b) { return b ? gcd (b, a%b) : a; }