zoukankan      html  css  js  c++  java
  • Codeforces Round #554 (Div. 2) C. Neko does Maths(GCD(a,b) = GCD(a,b-a))

    传送门

    题意

      给出两个正整数 a,b;

      求解 k ,使得 LCM(a+k,b+k) 最小,如果有多个 k 使得 LCM() 最小,输出最小的k;

    思路

      刚开始推了好半天公式,一顿xjb乱操作;

      后来,看了一下题解,看到一个引理:

      GCD(a,b) = GCD(a,b-a) = GCD(b,b-a);

    假设GCD(a,b) = c;
    a%c = 0;
    b%c = 0;
    那么(b-a)%c = 0;
    这证明了a和(b-a),b和(b-a)有公约数c;
    假设GCD(a,b-a)=c' > c;
    那么,a%c' = 0;
    (b-a)%c' = 0;
    (b-a)%c' = b%c'-a%c';
    所以 b%c' = 0;
    那么GCD(a,b) = c' > c,与假设矛盾;
    GCD(b,b-a)同理;
    故命题得证;
    简单证明

      有了这个引理后,解题思路变得异常清晰;

      首先,令 b > a;

      将 LCM(a+k,b+k) 转化一下:

      

      

      情况①,如果 a 与 b-a 不互素,那么 a+1 与 b-a 一定互素;

      情况②,a+k = x·(b-a),其中 x·(b-a) 是大于等于 a 的最小的 (b-a) 的倍数;

      情况③,枚举 b-a 的约数;

    •Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define ll long long
     6 
     7 ll a,b;
     8 
     9 ll GCD(ll a,ll b)
    10 {
    11     return a == 0 ? b:GCD(b%a,a);
    12 }
    13 ll LCM(ll a,ll b)
    14 {
    15     return a/GCD(a,b)*b;
    16 }
    17 ll F(ll k)
    18 {
    19     return (a+k)*(b+k)/GCD(a+k,b+k);
    20 }
    21 bool isSat(int i,ll k)//判断k是否可以更新为i-a
    22 {
    23     ll curK=i-a;
    24     if(curK < 0 || F(curK) != LCM(a+curK,b+curK))
    25         return false;
    26     if(F(curK) < F(k) || F(curK) == F(k) && curK < k)
    27         return true;
    28     return false;
    29 }
    30 ll Solve()
    31 {
    32     if(a > b)
    33         swap(a,b);
    34     int d=b-a;
    35     if(d == 0)
    36         return 0;
    37 
    38     ll k=1;
    39     for(;GCD(d,a+k) != 1;k++);///情况①
    40     for(int i=1;i*i <= d;++i)///情况③
    41     {
    42         if(d%i != 0)
    43             continue;
    44         if(isSat(i,k))///a+k=i
    45             k=i-a;
    46         if(isSat(d/i,k))///a+k=d/i
    47             k=d/i-a;
    48     }
    49     ///情况②,GCD()为定值,k越小LCM()就越小
    50     ll x=(a/d+(a%d == 0 ? 0:1))*d;///a+k=k*d(k*d:>=a的最小的d的倍数)
    51     if(isSat(x,k))
    52         k=x-a;
    53 
    54     return k;
    55 }
    56 int main()
    57 {
    58     scanf("%lld%lld",&a,&b);
    59     printf("%lld
    ",Solve());
    60 
    61     return 0;
    62 }
    View Code

    分割线:2019.7.23

    •新想法

      GCD(b-a , a+k) = f(b-a);

      f(b-a) 表示 b-a 的约数;

      当 GCD(b-a,a+k) 确定后,k 越小则 LCM(a+k,b+k) 就越小;

      假设 GCD(b-a,a+k) = f;

      ①如果 a 本身就为 f 的倍数,且 GCD(b-a,a) = f;

      那么 k = 0 是满足当前条件下,使得 LCM(a+k,b+k) 最小的最优解;

      ②反之,如果 a 不为  f 的倍数,那么,找到 ≥ a 的最小的 x·f,并判断 GCD(b-a,x·f) ?= f;

        1)如果 GCD(b-a,x·f) = f;

          那么 k = x·f-a 是满足当前条件下,使得 LCM(a+k,b+k) 最小的最优解;

        2)如果 GCD(b-a,x·f) ≠ f;

          那么 GCD(b-a,(x+1)·f)一定等于 f;

      GCD(b-a,x·f) = GCD(y·f,x·f) = f·GCD(x,y);

      判断 GCD(b-a,x·f) ?= f ⇔ 判断 GCD(y,x) ?= 1;

      如果 GCD(y,x) ≠ 1,那么一定有 GCD(y,x+1) = 1;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define GCD(a,b) __gcd(a,b)
     4 #define ll long long
     5 
     6 ll a,b;
     7 
     8 ll g(ll k)
     9 {
    10     return (a+k)/GCD(a+k,b+k)*(b+k);
    11 }
    12 void update(ll f,ll &k)
    13 {
    14     ll x=a/f+(a%f != 0);///找到使得x·f ≥ a的最小的x
    15     ll y=(b-a)/f;
    16 
    17     if(GCD(x,y) != 1)
    18         x++;
    19 
    20     ///判断是否更新k
    21     ll cur=x*f-a;
    22     if(k == -1 || g(k) > g(cur))
    23         k=cur;
    24     else if(g(k) == g(cur))
    25         k=min(k,cur);
    26 }
    27 ll Solve()
    28 {
    29     if(a == b)
    30         return 0;
    31     if(b < a)
    32         swap(a,b);
    33 
    34     ll k=-1;
    35 
    36     for(ll i=1;i*i <= b-a;++i)
    37     {
    38         if((b-a)%i != 0)
    39             continue;
    40 
    41         update(i,k);
    42         update((b-a)/i,k);
    43     }
    44 
    45     return k;
    46 }
    47 int main()
    48 {
    49     scanf("%lld%lld",&a,&b);
    50     printf("%lld
    ",Solve());
    51 
    52     return 0;
    53 }
    View Code

          

  • 相关阅读:
    Python基础知识二
    Django1-10-5管理界面中文设置
    人之初
    一句话解释wifi、蓝牙、4g的意思
    如何完美备份旧手机到新手机
    问题解决 --- surface go sd卡槽不识别问题
    反调试技术
    wireshark学习心得
    Socket编程,网络编程
    asm 知识总结
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10770704.html
Copyright © 2011-2022 走看看