算法刷题-数论-试除法求约数、约数个数、约数之和、最大公约数(辗转相除法)
文章目錄
- acwing869. 試除法求約數
- acwing870. 約數個數
- acwing871. 約數之和
- acwing872. 最大公約數
acwing869. 試除法求約數
acwing869. 試除法求約數
試除法求一個數的所有約數:從小到大枚舉,如果當前枚舉的數是原數的約數,就記錄下來(或者輸出)。
優化:如果 d能整除n的話,那么 n/d也能整除n;比如,3能整除6,那么 6/3=2,2也能整除6.因為約數是一對一對出現的。
這里的的優化是只枚舉較小的約數d,另一個可以直接n/d算出來,這樣的話只需要枚舉到n\sqrt{n}n?即可。
試除法求一個數所有約數,時間復雜度O(n)O(\sqrt{n})O(n?)
ac代碼
#include<bits/stdc++.h> using namespace std;//用vector來存所有約數 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);//邊界情況,i == n/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);//下面這種寫法,避免行末空格,在PAT這種OJ上會卡掉!cout<<res[0];for(int i;i<res.size(); i++) cout<<" "<<res[i];cout<<endl;}}acwing870. 約數個數
acwing870. 約數個數
分析:
約數個數基于算術基本定理
來源于:維基百科
假設N分解質因數(下面的p1,p2,...,pkp_1,p_2,...,p_kp1?,p2?,...,pk?都是質數)的結果是:
N=p1a1×p2a2×...×pkakN={p_1}^{a_1}\times{p_2}^{a_2}\times...\times{p_k}^{a_k}N=p1?a1?×p2?a2?×...×pk?ak?
則N的約數個數就等于(a1+1)×(a2+1)×...×(ak+1)(a_1+1)\times(a_2+1)\times...\times(a_k+1)(a1?+1)×(a2?+1)×...×(ak?+1)
所以這道題,最后的那個數N是給定的所有數的乘積,對N進行分解因式,其實,可以對乘起來之前的每一個數分解質因數,相同的因數,次冪累加起來。
用到分解質因數的知識,請移步筆者另一篇文章:
算法刷題-數論-質數的判定、分解質因數、篩質數中分解質因數的知識點。
ac代碼
#include<bits/stdc++.h> 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 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;//約數個數:套公式(1+a1)(1+a2)...(1+ak)for(auto prime : primes) res = res*(prime.second+1) % mod;cout<<res<<endl;}acwing871. 約數之和
acwing871. 約數之和
分析:
假設N分解質因數的結果是:
N=p1a1×p2a2×...×pkakN={p_1}^{a_1}\times{p_2}^{a_2}\times...\times{p_k}^{a_k}N=p1?a1?×p2?a2?×...×pk?ak?
則這個數N的約數之和等于
(p10+p11+p12+...+p1a1)×(p20+p21+p22+...+p2a2)×...×(pk0+pk1+pk2+...+pkak)(p_{1}^{0}+p_{1}^{1}+p_{1}^{2}+...+p_{1}^{a_{1}})\times(p_{2}^{0}+p_{2}^{1}+p_{2}^{2}+...+p_{2}^{a_{2}})\times...\times(p_{k}^{0}+p_{k}^{1}+p_{k}^{2}+...+p_{k}^{a_{k}})(p10?+p11?+p12?+...+p1a1??)×(p20?+p21?+p22?+...+p2a2??)×...×(pk0?+pk1?+pk2?+...+pkak??)
以上稱為“約數和定理”,在小學奧數中有應用。
補充:已知pap^apa的底數p,指數a,如何快速求出p0+p1+...+pap^0+ p^1+...+p^ap0+p1+...+pa?
有以下代碼
//求(p^0+ p^1+...+p^a)的代碼 int t =1; while(a--) t = t* p +1;ac代碼
#include<bits/stdc++.h> 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 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 prime : primes){int p = prime.first , a = prime.second; //分別是底數和指數LL t =1;//對每個質因子,求(p^0+ p^1+...+p^k)while(a--) t = (t * p +1) %mod;res = res * t % mod;}cout<<res<<endl;}acwing872. 最大公約數
acwing872. 最大公約數
輾轉相除法的核心:
(a,b)的最大公約數 =(b,a mod b)的最大公約數
amodb=a??ab?b=a?kb,k為常數a\ mod \ b = a-\lfloor \frac{a}{b}\rfloor b =a - kb,k為常數a?mod?b=a??ba??b=a?kb,k為常數
怎么證明呢?思想是證明(a,b)的公約數 和(b, a mod b)的公約數完全相同,則它們的最大公約數也相同。等價表述是,任何1個(a,b)的公約數,都是(b,a mod b)的公約數;反過來,任何1個(b,a mod b)的公約數,都是(a,b)的公約數,那么(a,b)的公約數 和(b, a mod b)的公約數完全相同。
具體證明過程略,提示:會用到數論里面的結論,若d能整除a,d能整除b,則d整除k1a+k2b,k1,k2k_1a+k_2b,k_1,k_2k1?a+k2?b,k1?,k2?是常數。
輾轉相除法模板解釋:
int gcd(int a, int b){//如果b !=0 則返回 gcd(b, a mod b)//如果 b==0,則返回 a ,因為0和a的最大公約數areturn b ? gcd(b, a %b) :a; }AC代碼
#include<bits/stdc++.h> using namespace std;int gcd(int a, int b){return b ? gcd(b, a %b) :a; } int main(){int n;cin >> n;while(n--){int a, b;scanf("%d%d",&a,&b);printf("%d\n",gcd(a,b));}}總結
以上是生活随笔為你收集整理的算法刷题-数论-试除法求约数、约数个数、约数之和、最大公约数(辗转相除法)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PAT甲级1059 Prime Fact
- 下一篇: Geany编辑器怎么使中文不报错?