试除法是一个很好的办法。这个算法的大致意思是让小于 n 的数都和 n 相除,如果余数为零可以判断为合数。
有了大致思路还不行,还可以优化。合数都是成对出现的,对吧。我们用 n 除以 i,余数为零,那么商也是另一个约数。
#include<iostream>#include<algorithm>#include<vector>usingnamespace std;intmain(){int n; cin >> n;while (n -- ){int m; cin >> m; vector<int> p;for (int i =1; i <= m / i; i ++){if (m % i ==0){p.push_back(i);if (m / i != i) p.push_back(m / i); } }sort(p.begin(),p.end());for (int i =0; i <p.size(); i ++) cout <<p[i] <<' '; cout << endl; }}
时间复杂度分析
约数个数
给定一个正整数怎么求约数的个数,此时需要一个定理,伟大的欧几里得数学家曾发现的。
算术基本定理
原理分析
#include<iostream>#include<algorithm>#include<unordered_map>usingnamespace std;constint N =1e9+7;intmain(){int n; cin >> n;longlong res =1; unordered_map<int,int> hs;while (n -- ){int m; cin >> m;for (int i =2; i <= m / i; i ++){ //枚举到 i*i <= mif (m % i ==0){while (m % i ==0){hs[i] ++; m /= i; } } }if (m >1) hs[m]++; // 只存在一个大于根号m的数是m的分解质数 }for (auto prime : hs) res = res * (prime.second +1) % N; cout << res;}
时间复杂度分析
约数之和
给定一个正整数,求他的约数的和。
原理分析
#include<iostream>#include<algorithm>#include<unordered_map>usingnamespace std;constint N =1e9+7;longlonghorner(int p,int x){longlong res =1;for (int i =0 ; i < x; i ++){ res = (res * p +1) % N; }return res;}intmain(){int n ; cin >> n; unordered_map<int,int> primes;while (n -- ){int m ; cin >> m;for (int i =2; i <= m / i; i ++){if (m % i ==0){while (m % i ==0){primes[i] ++; m /= i; } } }if (m >1) primes[m] ++; }longlong res =1;for (auto prime : primes){ res = res *horner(prime.first,prime.second) % N; } cout << res;}
时间复杂度分析
最大公约数
最大公约数就比较简单了,小学都学过,辗转相除法计算,就不多说了。
#include<iostream>#include<algorithm>usingnamespace std;intgcd(int a ,int b){return a ==0? b :gcd( b % a, a);}intmain(){int n; cin >> n;while (n -- ){int a, b; cin >> a >> b; cout <<gcd(a, b) << endl; }}
时间复杂度分析
递归函数的时间复杂度,一般用 master theorem 来分析,可讲的就多了,新开另一个来说。但这里又引入了 mod 运算,主定理也解决不了,可就难的多了。这里贴一个大佬的分析。