试除法是一个很好的办法。这个算法的大致意思是让小于 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; }}
任何一个正整数且不是质数的数 N 都可以分解为 N=p1a1∗p2a2∗⋯∗pnan ,其中任意一个 p 都是质数且 p1<p2<⋯<pn 。这是 N 的标准分解式。
原理分析
任何一个 N 可以分解为 p1a1∗p2a2∗⋯∗pnan,而任何一个 N 的合数都可以表示为p1b1∗p2b2∗⋯∗pnbn,其中 0<=bi<=ai。那么 N 的合数的个数不就是一个组合数 ∏i=1n(1+ai),我们按照算术基本定理计算就可。
#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;}
时间复杂度分析
最外层时间 n,里层 for 循环时间为 m, 最里层 while 循环均摊到 for 循环的时间为 1,所以总的时间复杂度 O(n∗m)。
约数之和
给定一个正整数,求他的约数的和。
原理分析
由算术基本定理可得,一个正整数可以分解为 N=p1a1∗p2a2∗⋯∗pnan,而任何一个 N 的合数都可以表示为 p1b1∗p2b2∗⋯∗pnbn,其中 0<=bi<=ai。那么约数之和可以表示为 (p11+p12+⋯+p1a1)∗⋯∗(pn1+pn2+⋯+pnan),可以简洁的表示为 ∏i=1n∑j=1aipij
#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 运算,主定理也解决不了,可就难的多了。这里贴一个大佬的分析。