寒假训练题目LCM

文章介绍了当给定整数n时,如何找到使得a+b=n的情况下a*b最小值的算法。对于质数n,a和b必须互质,通过基本不等式确定a和b的最优值。对于合数n,通过枚举n的因数并利用最大公约数和最小公倍数关系找到最小值。文章提供了具体的思路和部分伪代码实现。
摘要由CSDN通过智能技术生成

一,题目

二,思路

1,当n为质数的时候。设a+b=n,g为gcd(a,b),此时,a可以表示为x*g,b可表示为y*g,(x和y是未知的普通的数,设此数是为了方便表示,无他目的),那么(x+y)*g=n,如果n是质数,那么g只能等于1或n,因为x和y是正整数,所以x+y>1,所以x+y=n,g=1,所以gcd(a,b)=1,所以a和b必然互质,而lcm(a,b)=a*b/gcd(a,b)。这时我们发现,求lcm(a,b)的问题转化为a+b为定值,求a*b最小值的问题。根据基本不等式,a+b为定值时,a和b的差越大,a*b越小,所以a和b其中一个为1,另一个为n-1。

2,(1)当n为合数的时候,设a+b=n,g为gcd(a,b),此时,a可以表示为x*g,b可表示为y*g,因为(x+y)*g=n,所以n可表示为z*g(所以说gcd(a,b)是n的一个因数)。所以a+b=n<=>x*g+y*g=z*g。忽略g,这时我们发现,求lcm(a,b)的问题转化为x+y为定值z,求x*y的最小值,依旧根据基本不等式,x+y为定值时,x和y差越大,x*y越小。所以x和y其中一个为1,另一个为z-1;把g拿过来讨论,我们只要枚举每个满足条件的g(或者说n的因数),把这时的x*y最小值找出来就行。

(2)但此时有个问题,n可以是1e9。所以不能暴力枚举。但我们发现,当x和y其中一个是1,另一个是z-1时,a+b=n<=>g+(z-1)*g=z*g,令x=1,y=z-1,,则a=g,b=y*g所以此时(y+1)*g=z*g,

g+y*g=z*g,我们发现,枚举g的同时,z也被枚举,比如6这个数,枚举1的同时6被枚举,枚举2

的同时,3也被枚举。所以我们只要枚举差不多一半的因数g得到的结果,因为枚举另一半的与之对应的数z枚举得到的结果是一样的。这时的时间复杂度为O();

举个例子:n=100

当g=2时,z=50,y*g=98,a(即g)和b(即y*g)最小公倍数为98.

当g=4时,z=25,y*g=96,a(即g)和b(即y*g)最小公倍数为96.

当g=5时,z=20,y*g=95,a(即g)和b(即y*g)最小公倍数为95.

当g=10时,z=10,y*g=10,a(即g)和b(即y*g)最小公倍数为10.

当g=20时,z=5,y*g=95,a(即g)和b(即y*g)最小公倍数为95.

当g=25时,z=4,y*g=96,a(即g)和b(即y*g)最小公倍数为96.

当g=50时,z=2,y*g=98,a(即g)和b(即y*g)最小公倍数为98.

我们可以看到上下是对称的,所以我们只要枚举差不多一半的因数g得到的结果,因为枚举另一半的与之对应的因数z枚举得到的结果是一样的。

(3)总结,现在我们要做的是根据g+y*g=z*g<=>a+b=n这个式子,先枚举n的每一个因数g,用MIN对比每一个g和y*g最大公因数,如果MIN大于这个最大公因数,拿ans储存这个g,枚举到即可。

三,代码

(由于本人太蒟蒻,枚举g+y*g=z*g中g的每一个数的时候,总是出现问题,这里就不枚举g了,枚举z算了)

#include<iostream>
#define int long long
#define uep(z,a,b) for(int z=a;z<=b;++z)
#define rep(z,a,b) for(int z=a;z>=b;--z)
#define pb push_back
#define pf pudh_front
using namespace std;
int gcd(int a, int b)
{
    while (a ^= b ^= a ^= b %= a);
    return b;
}
int f(int n)
{
    int ans = 1, MIN = 1000000001;
    for (int z = 2; z * z <= n; ++z)
    {
        if (n % z == 0)
        {
            int a = n / z, b = n - a;
            int lcm = a * b / gcd(a, b);
            if (lcm < MIN) ans = z, MIN = lcm;
        }
    }
    return ans;
}
signed main()
{
    int t, n;
    cin >> t;
    while (t--)
    {
        cin >> n;
        int ans = f(n), tmp = n / ans;
        if (ans != 1) cout << tmp << " " << n - tmp << endl;
//如果ans进入f函数for循环出来后仍然为1,那么说明n是质数,这时要输出1和n-1而不是上面的代码。
        else cout << 1 << " " << n - 1 << endl;
    }
    return 0;
}

(不会有人真从头到尾全看完了吧,这题很简单,我只是用另一种办法来水贴)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值