• POJ 1061 青蛙的约会(拓展欧几里得求同余方程,解ax+by=c)


    青蛙的约会
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 122871   Accepted: 26147

    Description

    两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。 
    我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。 

    Input

    输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。

    Output

    输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"

    Sample Input

    1 2 3 4 5

    Sample Output

    4

    Source

     

    题目分析

    首先,我们可以轻松的列出方程: 
    设走了t步,x,y,m,n,L含义如题。 
    x+m*t≡y+n*t (mod L) 
    移项:(x-y)+t(m-n)≡0(mod L) 
    这个式子等价于(x-y)+t(m-n)=kL 
    //t和k才是未知数

    再移项:kL-t(m-n)=(x-y) 
    为了化出不定方程的标准形式(不化也可以),再改成: 
    kL+t(n-m)=(x-y) 
    n-m=p,x-y=q 
    kL+tp=q 
    //再次重申,t和k才是未知数! 
    上式已经是标准的不定方程了,然后怎么解它呢?

    以下是重点 
    首先,它有解的前提是gcd(L,p)|q。(整除符号,不是或运算(QωQ)) 
    所以我们先求gcd(L,p)。做一次拓欧,求出gcd(L,p),同时我们求出了(拓欧的)x0,y0先放着。(为了不和题目的x,y冲突) 
    接着,如果gcd(L,p)不整除q,那么之后无法做下去了,此题无解。 
    这里写图片描述

     

     1 #include<iostream>
     2 #include<string>
     3 #include<cmath>
     4 #include<algorithm>
     5 usingnamespace std;
     6 
     7 __int64 x,y,a,b,c,d;
     8 __int64 n,m,X,Y,L;
     9 
    10 __int64 gcd(__int64 a,__int64 b)
    11 {
    12     __int64 t,d;
    13     if(b==0)
    14     {
    15         x=1;
    16         y=0;
    17         return a;
    18     }
    19     d=gcd(b,a%b);
    20     t=x;
    21     x=y;
    22     y=t-(a/b)*y;
    23     return d;
    24 }
    25 
    26 int main()
    27 {
    28     while(scanf("%I64d%I64d%I64d%I64d%I64d",&X,&Y,&m,&n,&L)==5)
    29     {
    30         a=n-m;
    31         b=L;
    32         c=X-Y;
    33         d=gcd(a,b);
    34         if(c%d!=0)
    35         {
    36             printf("Impossible
    ");
    37             continue;
    38         }
    39         x=x*(c/d);
    40         y=y*(c/d);
    41 
    42         /*通解:
    43         x1=x+b/d*t;
    44         y1=y-a/d*t;
    45         t为任意整数
    46         */
    47         //找最小的x1,即求x+b/d*t最小,那么只有t为某一个数时才最小
    48         //显然t必须与x正负相反才有最小,那么就看做x-b/d*t,这个式子的最小值便是t=x/(b/d)时,注意这是整型除法
    49         __int64 k=x*d/b;
    50         k=x-k*b/d;
    51         if(k<0)
    52             k+=b/d;
    53         printf("%I64d
    ",k);
    54     }
    55     return0;
    56 }
     1 #include <iostream>  
     2 #include <cstdio>  
     3 #include <cstring>  
     4 #include <cmath>  
     5 #include <vector>  
     6 #include <string>  
     7 #include <queue>  
     8 #include <stack>  
     9 #include <algorithm>  
    10 
    11 #define INF 0x7fffffff  
    12 #define EPS 1e-12  
    13 #define MOD 1000000007  
    14 #define PI 3.141592653579798  
    15 #define N 100000  
    16 
    17 using namespace std;  
    18 
    19 typedef long long LL;  
    20 typedef double DB;  
    21 
    22 LL e_gcd(LL a,LL b,LL &x,LL &y)  
    23 {  
    24     if(b==0)  
    25     {  
    26         x=1;  
    27         y=0;  
    28         return a;  
    29     }  
    30     LL ans=e_gcd(b,a%b,x,y);  
    31     LL temp=x;  
    32     x=y;  
    33     y=temp-a/b*y;  
    34     return ans;  
    35 }  
    36 
    37 LL cal(LL a,LL b,LL c)  
    38 {  
    39     LL x,y;  
    40     LL gcd=e_gcd(a,b,x,y);  
    41     if(c%gcd!=0) return -1;  
    42     x*=c/gcd;  
    43     b/=gcd;  
    44     if(b<0) b=-b;  
    45     LL ans=x%b;  
    46     if(ans<=0) ans+=b;  
    47     return ans;  
    48 }  
    49 
    50 int main()  
    51 {  
    52     LL x,y,m,n,L;  
    53     while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF)  
    54     {  
    55         LL ans=cal(m-n,L,y-x);  
    56         if(ans==-1) printf("Impossible
    ");  
    57         else printf("%lld
    ",ans);  
    58     }  
    59     return 0;  
    60 }  
    View Code
     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 using namespace std;
     6 long long x, y, m, n, l, k, t, d, va, vb, ba, bb;
     7 long long extgcd(long long a, long long b, long long &x, long long &y)
     8 {
     9     long long d = a;
    10     if (b != 0)
    11     {
    12         d = extgcd(b, a%b, y, x);
    13         y = y - a / b * x;
    14     }
    15     else
    16     {
    17         x = 1; y = 0;
    18     }
    19     return d;
    20 }
    21 int main()
    22 {
    23     cin >> ba >> bb >> va >> vb >> l;
    24     m = va - vb; n = bb - ba;
    25     d = extgcd(m, l, x, y);
    26     if (n%d != 0)
    27     {
    28         puts("Impossible");
    29         return 0;
    30     }
    31     t = l / d;
    32     k = (x*(n / d) % t + t) % t;
    33     if (k < 0) k += l;
    34     cout << k << endl;
    35     return 0;
    36 }

    ax+by=c问题

     

    问题:ax+by=c,已知a、b、c,求解使该等式成立的一组x,y。其中a、b、c、x、y均为整数

     

    a,b的最大公约数为gcd(a,b)。如果c不是gcd(a,b)的倍数,则该等式无解,因为等式左边除以gcd(a,b)是整数,

    而等式右边除以gcd(a,b)后为小数。(根据解方程的时候,在等式的左右两边同时除以非0的整数,等式依然成立)

     

    因此,只有当c是gcd(a,b)的倍数的时候,该等式有解。这样,可以通过计算使ax1+by1=gcd(a,b)成立的x1、y1,

    然后有x=(c/gcd(a,b))*x1,y=(c/gcd(a,b))*y1,得到x,y。

     1 // 等式ax+by=c,已知a、b、c,求x和y。  
     2 // 解该线性方程等同于解同余式ax = c(mod b)  
     3 // 返回值表示是否有解,true有解,false无解  
     4 bool linear_equation(int a, int b, int c, int &x, int &y)  
     5 {  
     6     int n = extended_euclid(a, b, x, y);  
     7     if(c%n)  
     8         return false;  
     9     int k = c/n;  
    10     x *= k;  
    11     y *= k;  
    12     return true;  
    13 }  
  • 相关阅读:
    tomcat shutdown后,进程还存在linux系统中的解决办法
    nginx反向代理tcp协议的80端口
    redis集群搭建中遇到的一些问题
    《将博客搬至CSDN》
    最短路路径(1.1版待更新)
    线段树
    SDUT 3341 数据结构实验之二叉树二:遍历二叉树
    二叉树的遍历
    爆头题HDU
    图的入度和出度以及图的新的存储形式
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/8453049.html
Copyright © 2020-2023  润新知