• 「洛谷P1516」 青蛙的约会


    洛谷题号:P1516

    出处:?

    主要算法:数论

    难度:4.4

    思路分析:

           典型的同余方程。由于是纬线,绕一圈是可以绕回来的,所以是可以取模的。

      阅读题目,很容易得到同余方程$ x + tm ≡ y + tn (mod L)$

      于是我们可以通过Exgcd来求解。先转化为不定方程 $ x + tm - y - tn = sL $

      整理得 $ (m - n)t - Ls = y - x $

      设 $a = n - m, b = L, c = x - y$,代入可得 $ -at - bs = -c $,即 $ at + bs = c $

      因此通过先求解 $ at + bs = gcd(a, b) $,最后就能够解得一组特解了。转化成最小正整数解即可。

      然而要处理的事情还有很多。首先我们来想如何得到最小正整数解。

      设答案为$x$,我们得到的特解为$x_0$,则根据我们的公式一定有 $ x_0 = x + k * b / gcd(a, b) $。我们可以把它看做出发的形式,即$ x = x_0 \% (b / gcd(a, b)) $。

      因此我们的答案就是$ x \% (b / gcd(a, b)) $ …… ? 万一$x leq 0$?我们的答案应该是 $ (x + (b / gcd(a, b)) \% (b / gcd(a, b) $,防止爆负数。

      但是考虑一下$ b/gcd(a,b) 与 a, b$的符号,若$a, b$同号那没事,如果$a, b$异号且$ a < 0, b > 0$,那么情况就有点麻烦了……… $ gcd(a, b) $肯定小于0,而$b > 0$,所以 $ b / gcd(a, b) $ 一定小于0,因此按照这样的做法,答案不仅无法变成最小正整数解,反而更小了……

      有没有一种方法来避免$ a < 0, b > 0$这种情况呢?

      考虑可不可以永远保持$a$为正数。

      $ax + by = c$ 与 $-ax + by = -c$的解是否完全一样?

      乍一眼看不出来,可以转化为同余方程的形式,那么前者就能够变成$ c ≡ ax (mod b) $,后者就能够变成$ ax ≡ c (mod b) $。看来是完全一样的。

      因此当$a < 0$时,$a$和$c$转换成相反数就可以了。

    代码注意点:

      long long

    Code

    /*By QiXingzhi*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    #define int ll
    const int N = 100010;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
        return x * w;
    }
    int x,y,m,n,L,s,t,a,b,c,g;
    int gcd(int a, int b){
        return b==0?a:gcd(b,a%b);
    }
    void exgcd(int a, int b){
        if(b == 0){
            t = 1;
            s = 0;
            return;
        }
        exgcd(b,a%b);
        int tmp = t;
        t = s;
        s = tmp - a/b * s;
    }
    #undef int
    int main(){
    #define int ll
        //freopen(".in","r",stdin);
        x = r, y = r, m = r, n = r, L = r;
        a = n - m;
        b = L;
        c = x - y;
        if(a < 0){
            a = -a;
            c = -c;
        }
        g = gcd(a,b);
        exgcd(a,b);
        t *= c / g;
        s *= c / g;
        if(c % g != 0){
            printf("Impossible");
            return 0;
        }
        printf("%lld",(t + (b/g)) % (b/g));
        return 0;
    }
  • 相关阅读:
    HTTP状态码汇总
    树遍历以及图遍历的方法
    HashMap之扩容机制
    MySQL常见的七种锁
    双亲委派机制及作用
    Java进程故障排查思路及步骤
    八大数据结构
    常见的十种排序算法
    使用TortoiseGit操作分支的创建与合并
    Storage Port Drivers
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9320449.html
Copyright © 2020-2023  润新知