网站模板没有html文件下载/英语培训
一、最大公约数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)=ab
证明:设x和y的最大公约数为a,则最小公倍数为(x/a)(y/a)a=xy/a,最大公约数和最小公倍数的乘积为xy/aa=xy,证毕。
int lcm(int a,int b){return a/gcd(a,b)*b;//注意技巧:先除再乘,可避免乘法溢出
}
三、唯一分解定理
任何一个大于1的自然数N,都可以唯一分解成有限个质数的乘积N=p1a1*p2a2*…*pn^an这里p1<p2<…<pn均为质数,各指数ai是正整数。
这样的分解称为N的标准分解式。
定理应用:
一个大于1的自然是N,根据其标准分解式,可以求出其正因子个数是(a1+1)(a2+1)…(an+1),全体正因子之和是(1+p1+p12+…+p1a1)(1+p2+p22+…+p2a2)…(1+pn+pn2+…+pnan)。
下面是唯一分解定理的粗糙代码实现:
#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;
}