算術基本定理及應用串講尤拉函式
阿新 • • 發佈:2019-01-28
主要有以下內容:
1. 質因子分解
2. 質因子個數
3. 求數N的所有因子之和
4. 算術基本定理角度看GCD和LCM
程式碼實現:
質因數分解,個數統計,求和
#include <cstdio> #include <math.h> #include <map> using namespace std; map<int, int> ans; int sz; map<int,int> f( int n ) { map<int,int> ans; int temp = sqrt(n); for( int i=2; i<=temp; i++ ) { while( n%i == 0 ) { ans[i]++; n /= i; } } if( n != 1 ) ans[n] = 1; return ans; } int main() { int n ; int cnt = 1; // 全體正因數個數 int sum = 1; // 全體正因數的和 scanf("%d", &n ); ans = f(n); map<int,int> :: iterator it; for( it = ans.begin(); it != ans.end(); it++ ) { printf("%d -> %d\n", it->first, it->second ); // 底數和指數 cnt = cnt * (it->second+1); sum *= (pow(it->first, it->second+1) - 1)/(it->first - 1); } printf("cnt = %d\n", cnt ); printf("sum = %d\n", sum ); return 0; }
算術基本定理角度求GCD和LCM的程式碼實現
#include <bits/stdc++.h> using namespace std; int prime[1000000] = { 1, 1 }; vector<int> ve; int sz; map<int,int> f( int n ) { map<int,int> ans; int temp = sqrt(n); for( int i=0; ve[i]*ve[i] <= n && i<sz ; i++ ) { ans[ve[i]]; while( n%ve[i] == 0 ) { ans[ve[i]] ++; n /= ve[i]; } } if( n != 1 ) ans[n] = 1; return ans; } int main() { /*提前預處理1e6以內的素數,並將素數放入一個新的陣列內*/ for( int i=2; i<1005; i++ ) { if( !prime[i] ) for( int j=i+i; j<1000000; j += i ) prime[j] = 1; } for( int i=0; i<1000000; i++ ) if( !prime[i] ) ve.push_back(i); map<int,int> ans1; map<int,int> ans2; int n, m; sz = ve.size(); while( scanf("%d%d", &n, &m ) != EOF ) { ans1.clear(); ans2.clear(); double gcd = 1; // 這裡定義為double double lcm = 1; ans1 = f(n); ans2 = f(m); map<int,int> :: iterator it; // 下面這兩個for迴圈是輸出產生的兩個map for( it = ans1.begin(); it != ans1.end(); it ++ ) { printf("%d %d\n", it->first, it->second ); } printf("-----------------\n"); for( it = ans2.begin(); it != ans2.end(); it ++ ) { printf("%d %d\n", it->first, it->second ); } if( ans1.size() > ans2.size() ) { for( it = ans1.begin(); it != ans1.end(); it++ ) { // 這裡解釋為什麼定義為double, 如果定義為整型,因為pow()的返回值型別是double,所以會造成計算結果的錯誤 // 我用codeblocks編譯器就會因為這個原因造成結果錯誤 // 當然用不同的計算機或者不同的編譯器產生的結果不同也是有可能的 gcd *= pow( it->first, min(it->second, ans2[it->first]) ); lcm *= pow( it->first, max(it->second, ans2[it->first]) ); } } else { for( it = ans2.begin(); it != ans2.end(); it++ ) { gcd *= pow( it->first, min(it->second, ans1[it->first]) ); lcm *= pow( it->first, max(it->second, ans1[it->first]) ); } } printf("gcd = %.0f\n", gcd ); printf("lcm = %.0f\n", lcm ); } return 0; }
尤拉函式:
對正整數n,尤拉函式是少於或等於n的數中與n互質的數的數目。
對於一個正整數N的素數冪分解N=P1^q1*P2^q2*...*Pn^qn.
Euler函式表達通式:euler(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),或者φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),
其中p1,p2……pn為x的所有素因數,x是不為0的整數。
euler(1)=1(唯一和1互質的數就是1本身)。
尤拉公式的延伸:一個數的所有質因子之和是euler(n)*n/2。
#include <cstdio> #include <math.h> using namespace std; typedef long long LL; LL oula( LL n ) { LL ans = n; int t = sqrt(n); for( int i=2; i <= t; i++ ) { if( n%i == 0 ) { ans = ans / i *(i-1); while( n%i ==0 ) n = n / i; } } if( n != 1 ) ans = ans/n * (n-1); return ans; } int main() { LL n; while( scanf("%lld", &n ), n ) { LL ans; ans = oula(n); printf("%lld\n", ans ); } return 0; }