(數論)最大公約數、最小公倍數、唯一分解定理
阿新 • • 發佈:2018-12-31
一、最大公約數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;
}