题目描述:给出lcm(a,b)和gcd(a,b),求a,b.
输入:输入数据有多组,每组占一行,包含两个整数gcd,lcm,这两个整数都小于2^63。
输出:对于每组测试数据升序输出a,b的值,如果有多组满足条件的a,b,则输出a+b最小的一对。
Sample Input
3 60
Sample Output
12 15
题目分析:因为(a*b)/gcd=lcm,那么(a/gcd*b/gcd)*gcd=lcm,因此(a/gcd * b/gcd)=lcm/gcd.题目即可转化为把lcm/gcd分解成两个互质的数使这两个的数和最小。只需将key=lcm/gcd
整数分解,然后深搜一下即可得到结果。代码如下:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#define inf ((long long)1<<61)///infinite的缩写,意为无穷大
#define Times 11
#define N 1000
#define C 201
using namespace std;
unsigned long long key,a,b,gd,lm,res_a,res_b,mini;///res为result的简写
int ct;
long long factor[N];///存储质因子(含相同的)
long long gcd(long long a,long long b)
{
if(b==0)
return a;
return gcd(b,a%b);
}
long long random(long long n)
{
return (long long)((double)rand()/RAND_MAX*n+0.5);
}
long long multi(long long a,long long b,long long m)
{
long long ans=0;
while(b)
{
if(b&1)
{
ans=(ans+a)%m;
b--;
}
b>>=1;
a=(a<<1)%m;
}
return ans;
}
long long quick_mod(long long a,long long b,long long m)
{
long long ans=1;
a%=m;
while(b)
{
if(b&1)
{
ans=multi(ans,a,m);
b--;
}
b>>=1;
a=multi(a,a,m);
}
return ans;
}
bool witness(long long a,long long n)///二次探测定理
{
long long m=n-1;
int j=0;
while(m&1==0)
{
m>>=1;
j++;
}
long long x=quick_mod(a,m,n);
if(x==1||x==n-1)
return false;
while(j--)
{
x=x*x%n;
if(x==n-1)
return false;
}
return true;
}
bool miller_rabin(long long n)
{
if(n==1) return false;
if(n==2) return true;
if(n&1==0) return false;
for(int i=1;i<=Times;i++)
{
long long a=random(n-2)+1;
if(witness(a,n)) return false;
}
return true;
}
long long pollard_rho(long long n,int c)///大整数的分解
{
long long x,y,g;
long long i=1,k=2;
x=random(n-1)+1;
y=x;
while(1)
{
i++;
x=(multi(x,x,n)+c)%n;
g=gcd(y-x,n);
if(g>1&&g<n)
return g;
if(y==x)
return n;
if(i==k)
{
y=x;
k<<=1;
}
}
}
void find(long long n,int k)
{
if(n==1)
return ;
if(miller_rabin(n))
{
ct++;
factor[ct]=n;
return ;
}
long long p=n;
while(p>=n)
p=pollard_rho(p,k--);
find(p,k);
find(n/p,k);
}
unsigned long long NumFactor[650];///存储质因子(不包含相同的)
int Num[65];///存储每个质因子的个数
int len;
void dfs(int cur,long long value)///cur为cursor的缩写,意为光标
{
long long s=1;
if(cur==len+1)
{
a=value;
b=key/value;
if(gcd(a,b)==1)
{
a*=gd;
b*=gd;
if(a+b<mini)
{
mini=a+b;
res_a=a<b?a:b;
res_b=a>b?a:b;
}
}
return ;
}
for(int i=0;i<=Num[cur];i++)
{
if(value*s>=mini)
return ;
dfs(cur+1,value*s);
s*=NumFactor[cur];
}
}
void solve(long long n)///将factor中的质因子不重复的按从小到大的顺序存储到Numfactor[],
{ ///同时Num[]记录每种素因子的个数
ct=0;
find(n,C);
sort(factor+1,factor+ct+1);
len=0;
memset(Num,0,sizeof(Num));
Num[0]=1;
NumFactor[0]=factor[1];
for(int i=2;i<=ct;i++)
{
if(NumFactor[len]!=factor[i])
{
len++;
NumFactor[len]=factor[i];
}
Num[len]++;
}
dfs(0,1);
}
int main()
{
while(scanf("%lld%lld",&gd,&lm)!=EOF)
{
if(gd==lm)
{
cout<<gd<<" "<<lm<<endl;
continue;
}
mini=inf;///mini等于inf或-1都可以
key=lm/gd;
solve(key);
cout<<res_a<<" "<<res_b<<endl;
}
return 0;
}
本文介绍了一种算法,用于解决给定最小公倍数(lcm)和最大公约数(gcd)的情况下找到两个整数a和b的问题。通过分解lcm/gcd并采用深度优先搜索策略来寻找满足条件且a+b最小的一对整数。
262

被折叠的 条评论
为什么被折叠?



