两个数的
gcd:辗转相除法
lcm: a*b / gcd(a,b)
int gcd(int a,int b){
return b==0 ? a : gcd(b,a%b);
}
int lcm(int a,int b){
int g = gcd(a,b);
return a*b / g;
}
快速gcd
int qgcd(int a, int b)
{
if(a==0) return b;
if(b==0) return a;
if(!(a&1)&&!(b&1))
return qgcd(a>>1,b>>1)<<1;
else if(!(b&1))
return qgcd(a,b>>1);
else if(!(a&1))
return qgcd(a>>1,b);
else
return qgcd(abs(a-b),min(a, b));
}
n个数的
lcm:(a * b * ……) / gcd(a,b,……)
int lcm(int n,int b[]){
int ms = 1;
int g = gcd(n,b);
for(int i=0;i<n;i++)
ms *= b[i];
return ms / g;
}
gcd:
方案一:
迭代 g = get_gcd(g,b[i]) (0<i<n, g = a[0]),来获得n个数的最大公约数。
int gcd(int a,int b){
return b==0 ? a : gcd(b,a%b);
}
int get_gcd(int n,int b[]){
int q = gcd(b[0],b[1]);
for(int i=2;i<n;i++)
q = gcd(q,b[i]);
return q;
}
方案二:
参考于:https://blog.csdn.net/achanss/article/details/89740472
求多个数的最大公约数采用反复用最小数模其它数的方法,即对其他数用最小数多次去减,直到剩下比最小数更小的余数。令n个正整数为x1,x2,…,xn,求多个数最大共约数的算法描述为:
- 找到x1,x2,…,xn中的最小非零项xj,若有多个最小非零项则任取一个
- xj以外的所有其他非0项xk用xk mod xj代替;
若没有除xj以外的其他非0项,则转到(4) - 转到(1)
- x1,x2,…,xn的最大公约数为xj,结束算法
int x[maxn],n;
void Get_gcd()
{
priority_queue<ll,vector<ll>,greater <ll> > q;
for(int i = 1;i<n;i++){
q.push(x[i] - x[i-1]);
}
ll mx_gcd = 1; //最大公约数
while(1){
int flag = 1;
priority_queue<ll,vector<ll>,greater <ll> > p;
while((!q.empty()) && (!q.top()) ){
q.pop();
}
if(q.empty()) break;
ll minc = q.top();
q.pop();
p.push(minc);
while(!q.empty()){
ll t = q.top();
q.pop();
t %= minc;
if(t!=0) flag = 0;
p.push(t);
}
if(flag){
mx_gcd = minc;
break;
}
q = p;
}
cout<<mx_gcd<<endl;
}
x个C(n,m)求最大公约数
- 最大公约数不会大于min(n)(这x个C(n,m)的n的最小值),最大质因子一定小于等于min(n)
- 我们知道C(n,m) = n ! m ! ( n − m ) ! \frac{n!}{m!(n-m)!} m!(n−m)!n!,C(n,m)每个质因子的个数:cal(n,pri[i]) - cal(m,pri[i]) - cal(n-m,pri[i]),cal函数是求解n!中质因子pri[i]的个数,这里的max(pri[i])(质因子最大值)小于等于min(n),显然这x组中质因子pri[i]个数最少的那组,就是最大公因数的质因子pri[i]的个数。
- ans *= pow(pri[i],个数),ans就是所求最大公因数
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100100;
struct In{
int n,m;
}a[maxn];
int pri[maxn],tot;
bool v[maxn];
int p[maxn]; //记录各素数的个数
void prime() //素数打表
{
memset(v,true,sizeof(v));
tot = 0;
for(int i=2;i<maxn;i++){
if(v[i]) pri[++tot] = i;
for(int j=1;j<=tot&&i*pri[j]<maxn;j++){
v[i*pri[j]] = false;
if(i%pri[j]==0) break;
}
}
}
int cal(int n,int p) //n!中素因子p的个数
{
int ans = 0;
while(n){
ans += n/p;
n /= p;
}
return ans;
}
int getgcd(int n,int m,int p) //C(n,m)中素因子p的个数
{
int q = cal(n,p) - cal(m,p) - cal(n-m,p);
return q;
}
int main(void)
{
int x,m,n;
int _min = inf;
prime();
cin>>x;
for(int i=0;i<x;i++){
cin>>a[i].n>>a[i].m;
_min = min(_min,a[i].n); //找min(n)
}
ll ans = 1;
for(int i=1;pri[i]<=_min;i++){
p[i] = inf; //初始化
for(int j=0;j<x;j++){
int r = getgcd(a[j].n,a[j].m,pri[i]);
p[i] = min(p[i],r); //找质因子pri[i]个数最少的那组
}
for(int j=0;j<p[i];j++)
ans *= (ll)pri[i]; //求gcd
}
printf("%lld\n",ans);
return 0;
}