1. 程式人生 > >(數論)最大公約數、最小公倍數、唯一分解定理

(數論)最大公約數、最小公倍數、唯一分解定理

一、最大公約數gcd

約數和倍數的定義(百度百科)

整數a除以整數b(b≠0) 除得的商正好是整數而沒有餘數,我們就說a能被b整除,或b能整除a。a稱為b的倍數,b稱為a的約數。
顯然,任何非0整數是0的約數,0不是任何數的約數。

int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}

二、最小公倍數lcm

定理:lcm(a,b)*gcd(a,b)=a*b

證明:設x和y的最大公約數為a,則最小公倍數為(x/a)*(y/a)*a=x*y/a,最大公約數和最小公倍數的乘積為x*y/a*a=x*y,證畢。

int lcm(int a,int
b){ return a/gcd(a,b)*b;//注意技巧:先除再乘,可避免乘法溢位 }

三、唯一分解定理

任何一個大於1的自然數N,都可以唯一分解成有限個質數的乘積N=p1^a1*p2^a2*…*pn^an這裡p1

#include<iostream>
#include<cmath>
using namespace std;

typedef struct{
    int x,y;
}node;

node a[1000];
int j=0;

int solve(int n){
    j=0;
    for(int i=2;i<=n;i++){
        if
(n%i==0){ int cnt=1; n/=i; while(n%i==0){ cnt++; n/=i; } a[j].x=i; a[j++].y=cnt; } } } int main() { int T,n; cin>>T; while(T--){ cin>>n; solve(n); for
(int i=0;i<j;i++){ cout<<a[i].x<<" "<<a[i].y<<endl; } } return 0; }

【例題Choose and divide UVA - 10375 】

題意:已知C(m,n)=m! / (n!*(m-n!)),輸入整數p,q,r,s(p>=q,r>=s,p,q,r,s<=10000),計算C(p,q)/C(r,s)。輸出保證不超過10^8,保留5位小數

【程式碼】
參考劉汝佳《演算法競賽入門經典》(第2版)

#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
#include<cstdio>
using namespace std;

const int maxn=10000+5;

vector<int>prime;
bool vis[maxn];
int e[maxn];

//把10000以內的所有素數給晒出來
void init(){
    memset(vis,0,sizeof(vis));
    for(int i=2;i<maxn;i++)
        for(int j=2*i;j<maxn;j+=i)
            vis[j]=1;
    for(int i=2;i<maxn;i++)
        if(!vis[i]) prime.push_back(i);
}
//一個一個整數用素數給消耗掉,轉化成素數指數冪形式(唯一分解定理)
void add_integer(int n,int d){
    for(int i=0;i<prime.size();i++){
        while(n%prime[i]==0){
            n/=prime[i];
            e[i]+=d;
        }
        if(n==1) break;
    }
}
//把整個階乘按照一個數一個數的拆成指數冪
void add_factorial(int n,int d){
    for(int i=1;i<=n;i++)
        add_integer(i,d);
}

int main()
{
    init();
    int p,q,r,s;
    while(cin>>p>>q>>r>>s){
        memset(e,0,sizeof(e));
        add_factorial(p,1);
        add_factorial(q,-1);
        add_factorial(p-q,-1);
        add_factorial(s,1);
        add_factorial(r-s,1);
        add_factorial(r,-1);
        double ans=1;
        for(int i=0;i<prime.size();i++)
            ans*=pow(prime[i],e[i]);
        printf("%.5lf\n",ans);
    }
    return 0;
}