2429 GCD & LCM Inverse 大整数分解质因数

本文探讨了给定最大公约数(GCD)和最小公倍数(LCM)时,如何寻找符合条件的两个正整数a和b。通过质因数分解、Miller-Rabin素性测试等算法,实现了一种有效的方法来解决这一逆问题。
GCD & LCM Inverse
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 3966 Accepted: 680

Description

Given two positive integers a and b, we can easily calculate the greatest common divisor (GCD) and the least common multiple (LCM) of a and b. But what about the inverse? That is: given GCD and LCM, finding a and b.

Input

The input contains multiple test cases, each of which contains two positive integers, the GCD and the LCM. You can assume that these two numbers are both less than 2^63.

Output

For each test case, output a and b in ascending order. If there are multiple solutions, output the pair with smallest a + b.

Sample Input

3 60

Sample Output

12 15
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<algorithm>
//看情况选择下列两个
//#define bignum unsigned long long
#define bignum unsigned __int64
using namespace std;
//求a,b的最大公约数
bignum gcd(bignum a,bignum b)
{
    return b==0?a:gcd(b,a%b);
}
//求a*b%c,因为a,b很大,所以要先将b写成二进制数,再加:例如3*7=3*(1+2+4);
bignum mulmod(bignum a,bignum b,bignum c)
{
    bignum cnt=0,temp=a;
    while(b)
    {
        if(b&1) cnt=(cnt+temp)%c;
        temp=(temp+temp)%c;
        b>>=1;
    }
    return cnt;
}
//求a^b%c,再次将b写成二进制形式,例如:3^7=3^1*3^2*3^4;
bignum powmod(bignum a,bignum b,bignum c)
{
    bignum cnt=1,temp=a;
    while(b)
    {
        if(b&1) cnt=mulmod(cnt,temp,c);//cnt=(cnt*temp)%c;
        temp=mulmod(temp,temp,c);//temp=(temp*temp)%c;
        b>>=1;
    }
    return cnt;
}
//Miller-Rabin测试n是否为素数,1表示为素数,0表示非素数
int pri[10]={2,3,5,7,11,13,17,19,23,29};
bool Miller_Rabin(bignum n)
{
    if(n<2) return 0;
    if(n==2) return 1;
    if(!(n&1)) return 0;
    bignum k=0,m;
    m=n-1;
    while(m%2==0) m>>=1,k++;//n-1=m*2^k
    for(int i=0;i<10;i++)
    {
        if(pri[i]>=n) return 1;
        bignum a=powmod(pri[i],m,n);
        if(a==1) continue;
        int j;
        for(j=0;j<k;j++)
        {
            if(a==n-1) break;
            a=mulmod(a,a,n);
        }
        if(j<k) continue;
        return 0;
    }
    return 1;
}
//pollard_rho 大整数分解,给出n的一个非1因子,返回n是为一次没有找到
bignum pollard_rho(bignum C,bignum N)
{
    bignum I, X, Y, K, D;
    I = 1;
    X = rand() % N;
    Y = X;
    K = 2;
    do
    {
        I++;
        D = gcd(N + Y - X, N);
        if (D > 1 && D < N) return D;
        if (I == K) Y = X, K *= 2;
        X = (mulmod(X, X, N) + N - C) % N;
    }while (Y != X);
    return N;
}
//找出N的最小质因数
bignum rho(bignum N)
{
    if (Miller_Rabin(N)) return N;
    do
    {
        bignum T = pollard_rho(rand() % (N - 1) + 1, N);
        if (T < N)
        {
              bignum A, B;
              A = rho(T);
              B = rho(N / T);
              return A < B ? A : B;
        }
    }
    while(1);
}
//N分解质因数,这里是所有质因数,有重复的
bignum AllFac[1100];
int Facnum;
void findrepeatfac(bignum n)
{
    if(Miller_Rabin(n))
    {
        AllFac[++Facnum]=n;
        return ;
    }
    bignum factor;
    do
    {
        factor=pollard_rho(rand() % (n - 1) + 1, n);
    }while(factor>=n);
    findrepeatfac(factor);
    findrepeatfac(n/factor);
}
//求N的所有质因数,是除去重复的
bignum Fac[1100];
int num[1100];
int len;
void FindFac(bignum n)
{
    len=0;
    //初始化
    memset(AllFac,0,sizeof(AllFac));
    memset(num,0,sizeof(num));
    Facnum=0;
    findrepeatfac(n);
    sort(AllFac+1,AllFac+1+Facnum);
    Fac[0]=AllFac[1];
    num[0]=1;
    for(int i=2;i<=Facnum;i++)
    {
        if(Fac[len]!=AllFac[i])
        {
            Fac[++len]=AllFac[i];
        }
        num[len]++;
    }
}
//dfs将key分解成两个互质的数的乘积,并且使这两个数和最小
/*
bignum Fac[200];
int num[200];
int len;(0-len);*/
bignum res_a,res_b;
bignum _min,key,com;
void dfs(int cur,bignum val)
{
    if(cur==len+1)
    {
        bignum a=val,b=key/val;
        if(gcd(a,b)==1)
        {
            a*=com,b*=com;
            if(a+b<_min)
            {
                _min=a+b;
                res_a=a<b ? a : b;
                res_b=a>b ? a : b;
            }
        }
        return ;
    }
    bignum s=1;
    for(int i=0;i<=num[cur];i++)
    {
        if(val*s>=_min)
        {
            return ;
        }
        dfs(cur+1,val*s);
        s*=Fac[cur];
    }
}
int main ()
{
    srand(time(NULL));
    bignum l,g;
    while(scanf("%I64u%I64u",&g,&l)!=EOF)
    {
        if(l==g)
        {
            printf("%I64u %I64u/n",g,l);
            continue;
        }
        //初始化
        key=l/g;
        FindFac(key);
        //初始化
        _min=(1<<63)-1;com=g;
        dfs(0,1);
        printf("%I64u %I64u/n",res_a,res_b);
    }
    return 0;
}
### 硬件加密算法中质因数分解的应用 在现代公钥密码学体系中,许多重要的加密技术依赖于大整数质因数分解难题。具体来说,RSA 加密算法的安全性基于这样一个假设:对于两个足够的素数 p 和 q,虽然容易计算它们的乘积 n=pq,但是要从已知的 n 反向求解原始的 p 和 q 却极其困难。 #### RSA 加密机制概述 当涉及到硬件实现时,RSA 密码体制利用了模幂运算来完成加/解密过程: - **密钥生成阶段**:选取两个不同且足够的随机素数 \(p\) 和 \(q\);计算其乘积 \(n = pq\) 作为公开参数的一部分; - **加密操作**:发送方通过接收者的公钥 \((e, n)\),将明文消息转换成对应的密文形式 \(c=m^e\bmod{n}\)[^1]; - **解密处理**:持有私钥 d 的接收者可以恢复原文 m=\(c^d\%{n}=m^{ed}\bmod{n}\)=\(m\bmod{n}\) ,这里 ed &equiv; 1 (mod &phi;(n)) 成立[^2]。 由于上述过程中涉及到了量的指数取模运算,因此高效的硬件设计成为提升性能的关键因素之一。专用集成电路 ASIC 或 FPGA 上实现了优化后的 Montgomery 模乘算法等加速手段,使得即使面对较长位长的数据也能保持良好的实时响应特性。 #### 质因数分解攻击的风险 然而值得注意的是,随着量子计算机的发展及其所支持的新一代高效因子化方法&mdash;&mdash;Shor&#39;s Algorithm 出现,传统意义上认为难以解决的规模整数分解问题可能不再安全。一旦能够实际部署并有效执行该类算法,则当前广泛使用的基于离散对数或椭圆曲线上的非对称方案都将面临严峻挑战。 ```python from sympy import isprime, mod_inverse def generate_keys(p, q): &quot;&quot;&quot;Generate public and private keys from primes.&quot;&quot;&quot; if not (isprime(p) and isprime(q)): raise ValueError(&#39;Both numbers must be prime.&#39;) n = p * q phi_n = (p - 1)*(q - 1) e = find_e(phi_n) d = mod_inverse(e, phi_n) return ((e, n), (d, n)) def encrypt(public_key, plaintext): &quot;&quot;&quot;Encrypt message using the public key&quot;&quot;&quot; e, n = public_key cipher_text = pow(plaintext, e, n) return cipher_text def decrypt(private_key, ciphertext): &quot;&quot;&quot;Decrypt message with the private key&quot;&quot;&quot; d, n = private_key plain_text = pow(ciphertext, d, n) return plain_text ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值