https://codeforces.com/contest/1152/problem/C

C. Neko does Maths

time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Neko loves divisors. During the latest number theory lesson, he got an interesting exercise from his math teacher.

Neko has two integers a and b. His goal is to find a non-negative integer k such that the least common multiple of a+k and b+k is the smallest possible. If there are multiple optimal integers k, he needs to choose the smallest one.

Given his mathematical talent, Neko had no trouble getting Wrong Answer on this problem. Can you help him solve it?

Input
The only line contains two integers a and b (1≤a,b≤109).

Output
Print the smallest non-negative integer k (k≥0) such that the lowest common multiple of a+k and b+k is the smallest possible.

If there are many possible integers k giving the same value of the least common multiple, print the smallest one.

Examples
inputCopy
6 10
outputCopy
2
inputCopy
21 31
outputCopy
9
inputCopy
5 10
outputCopy
0

题意:给定两个数,给两个数同时加上一个非负数,使得加完后的两个数的最小公倍数最小。如果有多个值可以使最小公倍数取得最小值,那么输出最小的那个值。

方法:枚举两个数所有可能的最小公倍数。

枚举方法有技巧。假设a>b,GCD(a+k,b+k) == GCD(a+k,a - b)这个结论其实是辗转相减法求GCD的一个步骤(辗转相减法本质上又是效率较低的辗转相除法,所以这个等式是可以证明的)。
然后枚举a-b的所有因子(这些因子就是a+k,b+k这两个数的GCD的备选项)。枚举n的因子只要从1枚举到sqrt(n),时间复杂度为根号n,可以接受。
然后配凑出一个k,使得a+k,b+k的最大公因数正好是上文枚举的因子。只要使得a+k这个数也含有这个因子即可。要找出最小的k,使得a+k含有一个已知的因子。计算k的式子如下:

a%fac[i] == 0 ? 0 : (a/fac[i]+1)*fac[i] - a

可以看到它其实是求出了最下的a+k,这个值就是**((a/fac)+1)fac*(我没想好这个式子应当怎么证明,但是可以感受出它的正确性),再减去a即可。
代码如下:

#include <bits/stdc++.h>
using namespace std;

int64_t fac[200005];
int main()
{
    int64_t n,m,i,j,k,ans,num,sum,a,b,c,tot,lcm;
    cin>>a>>b;
    if(a>b)
    {
        swap(a,b);
    }
    c = b - a,tot = 0;
    for(int64_t i = 1;i<=sqrt(c);i++)
    {
        if(c%i == 0) fac[tot++] = i,fac[tot++] = c/i;
    }
    if(tot == 0)
    {
        cout<<0;
        return 0;
    }
    //cout<<tot<<endl;
    ans = 0x3f3f3f3f3f3f3f;
    for(int64_t i = 0;i<tot;i++)
    {
        num = (a%fac[i] == 0 ? 0 : (a/fac[i]+1)*fac[i] - a);
        lcm = ((a+num)*(b+num))/fac[i];
        //cout<<num<<" "<<lcm<<"@@"<<endl;
        if(lcm < ans)
        {
            //cout<<"!!!"<<endl;
            ans = lcm;
            k = num;
        }
        else if(lcm == ans&&num<k) k = num;
    }
    printf("%lld\n",k);
    return 0;
}

代码转载自博客:https://www.cnblogs.com/youchandaisuki/p/10767833.html
如有侵权请联系删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值