数论 - GCD LCM - UVA 11388

数论 - GCD LCM - UVA 11388

题意:

T 组 测 试 数 据 , T组测试数据, T

每 组 包 括 两 个 正 整 数 , 分 别 表 示 一 个 最 大 公 约 数 G 和 最 小 公 倍 数 L 。 每组包括两个正整数,分别表示一个最大公约数G和最小公倍数L。 GL

要 求 输 出 满 足 条 件 的 a 和 b , 使 得 g c d ( a , b ) = G , l c m ( a , b ) = L 。 要求输出满足条件的a和b,使得gcd(a,b)=G,lcm(a,b)=L。 ab使gcd(a,b)=Glcm(a,b)=L

若 无 解 , 输 出 − 1 。 若无解,输出-1。 1

若 有 多 组 解 , 输 出 a 最 小 的 一 组 解 。 若有多组解,输出a最小的一组解。 a

Sample Input

2
1 2
3 4

Sample Output

1 2
-1

数据范围:

T ≤ 100 , G 和 L 不 超 过 2 31 T\le100,G和L不超过2^{31} T100GL231

Time limit: 1000 ms


分析:

由 题 意 , 根 据 a 和 b 的 最 大 公 约 数 和 最 小 公 倍 数 , 反 过 来 求 a 和 b 。 由题意,根据a和b的最大公约数和最小公倍数,反过来求a和b。 abab

我 们 知 道 : 我们知道:

设 a = P 1 a 1 P 2 a 2 . . . P k a k , b = P 1 b 1 P 2 b 2 . . . P k b k 设a=P_1^{a_1}P_2^{a_2}...P_k^{a_k},b=P_1^{b_1}P_2^{b_2}...P_k^{b_k} a=P1a1P2a2...Pkakb=P1b1P2b2...Pkbk

则 : 则: :

g c d ( a , b ) = P 1 m i n ( a 1 , b 1 ) P 2 m i n ( a 2 , b 2 ) . . . P k m i n ( a k , b k ) \qquad gcd(a,b)=P_1^{min(a_1,b_1)}P_2^{min(a_2,b_2)}...P_k^{min(a_k,b_k)} gcd(a,b)=P1min(a1,b1)P2min(a2,b2)...Pkmin(ak,bk)

l c m ( a , b ) = P 1 m a x ( a 1 , b 1 ) P 2 m a x ( a 2 , b 2 ) . . . P k m a x ( a k , b k ) \qquad lcm(a,b)=P_1^{max(a_1,b_1)}P_2^{max(a_2,b_2)}...P_k^{max(a_k,b_k)} lcm(a,b)=P1max(a1,b1)P2max(a2,b2)...Pkmax(ak,bk)

可 知 , 对 于 任 意 两 个 整 数 数 x , y , 设 它 们 的 质 因 子 P i 的 指 数 分 别 为 u i 和 v i , 可知,对于任意两个整数数x,y,设它们的质因子P_i的指数分别为u_i和v_i, x,yPiuivi

只 要 满 足 数 对 ( u i , v i ) = ( a i , b i ) 或 ( u i , v i ) = ( b i , a i ) , 就 能 够 找 到 满 足 条 件 的 一 组 解 ( x , y ) 只要满足数对(u_i,v_i)=(a_i,b_i)或(u_i,v_i)=(b_i,a_i),就能够找到满足条件的一组解(x,y) (ui,vi)=(ai,bi)(ui,vi)=(bi,ai)(x,y)

上述讨论是在有解的情形下讨论的。下面简要说明无解情况:

设 G = P 1 g 1 P 2 g 2 . . . P k g k , L = P 1 l 1 P 2 l 2 . . . P k l k 设G=P_1^{g_1}P_2^{g_2}...P_k^{g_k},L=P_1^{l_1}P_2^{l_2}...P_k^{l_k} G=P1g1P2g2...PkgkL=P1l1P2l2...Pklk

当 g i > l i 时 , 可 知 , 无 法 找 到 一 组 符 合 条 件 的 x , y , 使 得 m i n ( u i , l i ) = g i , m a x ( u i , l i ) = l i , 当g_i>l_i时,可知,无法找到一组符合条件的x,y,使得min(u_i,l_i)=g_i,max(u_i,l_i)=l_i, gi>lix,y使min(ui,li)=gimax(ui,li)=li

此 时 是 无 解 情 况 。 此时是无解情况。

那么如何确定最小解?

当 给 定 的 数 据 有 解 时 , 说 明 对 于 任 意 一 组 g i , l i , 都 有 g i ≤ l i , 当给定的数据有解时,说明对于任意一组g_i,l_i,都有g_i\le l_i, gi,ligili

我 们 要 输 出 a 最 小 的 解 , a 最 小 即 最 大 公 约 数 G , 此 时 b 也 唯 一 确 定 , 即 最 小 公 倍 数 。 我们要输出a最小的解,a最小即最大公约数G,此时b也唯一确定,即最小公倍数。 aaGb

具体落实代码:

① 、 对 输 入 的 G 和 L 进 行 因 数 分 解 , 用 一 个 同 一 个 数 组 存 储 质 因 子 , 用 两 个 数 组 分 别 存 储 对 应 的 指 数 。 ①、对输入的G和L进行因数分解,用一个同一个数组存储质因子,用两个数组分别存储对应的指数。 GL

② 、 若 G 和 L 中 , 存 在 某 个 质 因 子 的 指 数 g i > l i , 则 无 解 , 否 则 输 出 G 和 L 。 ②、若G和L中,存在某个质因子的指数g_i>l_i,则无解,否则输出G和L。 GLgi>liGL

由 于 G , L ≤ 2 31 , 我 们 仅 需 预 处 理 到 2 31 的 质 数 即 可 。 由于G,L\le 2^{31},我们仅需预处理到\sqrt{2^{31}}的质数即可。 G,L231231

时 间 复 杂 度 O ( G ) 时间复杂度O(\sqrt{G}) O(G )

代码:

#include
#include
#include
#include
#include
#include

#define ll long long

using namespace std;

const int N=65536;

int primes[N+10], idx;
int divisors[32], s[3][32], cnt; 
bool st[N+10];

void get_prime(int n)
{
     
    for(int i=2;i<=n;i++)
    {
     
        if(!st[i]) primes[idx++]=i;
        for(int j=0;primes[j]*i<=n;j++)
        {
     
            st[primes[j]*i]=true;
            if(i%primes[j]==0) break;
        }
    }
}

void get_divisors(int a,int b)
{
     
    int sqa=sqrt(a), sqb=sqrt(b);
    for(int i=0;primes[i]<=max(sqa,sqb);i++)
    {
     
        int p=primes[i];
        if(a%p==0||b%p==0)
        {
     
            divisors[cnt]=p;
            int k1=0, k2=0;
            while(a%p==0) 
            {
     
                k1++;
                a/=p;
            }
            while(b%p==0)
            {
     
                k2++;
                b/=p;
            }
            s[1][cnt]=k1;
            s[2][cnt++]=k2;
        }
    }
    if(a>1||b>1) 
    {
     
        if(a==b) divisors[cnt]=a, s[1][cnt]=s[2][cnt]=1, cnt++;
        else 
        {
     
            if(a>1) divisors[cnt]=a, s[1][cnt]=1, s[2][cnt++]=0;
            if(b>1) divisors[cnt]=b, s[1][cnt]=0, s[2][cnt++]=1;
        }
    }
}

int main()
{
     
    get_prime(N);
    
    int T;
    int a,b;
    cin>>T;
    while(T--)
    {
     
        cnt=0;
        memset(divisors,0,sizeof divisors);
        memset(s,0,sizeof s);
        
        cin>>a>>b;
        get_divisors(a,b);

        bool flag=true;
        ll res1=a, res2=b;
        for(int i=0;i<cnt;i++)
            if(s[1][i]>s[2][i])
            {
     
                flag=false;
                break;
            }

        if(!flag) puts("-1");
        else printf("%lld %lld\n",res1,res2);
    }
    
    return 0;
}

你可能感兴趣的:(数论,算法,数论,ACM)