poj 1061青蛙的约会 (数论:扩展的欧几里得算法)

来源:互联网 发布:广汽研究院工资算法 编辑:程序博客网 时间:2024/06/12 01:12

很直接的欧几里得算法题

为了叙述简明,我们不妨设输入数据为a,b,m,n,l

则很容易得到方程

[(m-n)*x+a-b] % l == 0

可改写为:

(m-n)*x-l*y == b-a

得到一个方程,根据扩展欧几里得算法解方程即可

最大公约数函数:

int gcd(int a, int b) {//证明省略return b==0?a:gcd(b,a%b);}

扩展欧几里得算法:

void expand_gcd(int a, int b, int d, int x, int y) {//其中d==gcd(a,b)if(b == 0) {d = a;x = 1;y = 0;}else {expand_gcd(b, a%b, d, y, x);//注意这里参数顺序的变化y -= x*(a/b);}}
这样不难解出方程(m-n)*x-l*y=gcd(m-n, l)的解(x0, y0),在(x0, y0)的基础上很容易解出原方程的解

代码如下:

#include <cstdio>#include <iostream>#include <algorithm>#define MAXN 10010#define LL long longusing namespace std;LL gcd(LL a, LL b) {    return b==0 ? a : gcd(b, a%b);}void expand_gcd(LL a, LL b, LL d, LL &x, LL &y) {    if(!b) {        d = a;        x = 1;        y = 0;    }    else {        expand_gcd(b, a%b, d, y, x);        y -= x*(a/b);    }}int main(void) {    LL a, b, m, n, l, x, y;    LL c, d;    cin >> a >> b >> m >> n >> l;    if(m > n) {        c = b - a;        d = gcd(m-n, l);        expand_gcd(m-n, l, gcd(m-n, l), x, y);    }    else {        c = a - b;        d = gcd(n-m, l);        expand_gcd(n-m, l, gcd(n-m, l), x, y);    }    if(c % d) {        printf("Impossible\n");    }    else {        LL ans;        ans = (x*c/d)%(l/d);//这一步不太容易理解,见下面注释        if(x*c/d <= 0) {            ans += (l/d);        }        cout << ans << endl;    }    return 0;}

ans = x*c/d很容易理解

因为x是原方程exp/c*gcd(m-n, l)的解

因此很容易得出原方程的一个解是ans = x*c/d;

但是为什么要mod(l/d)呢???

这是为了保证此时ans对应于两只青蛙第一次见面

设方程a*x+b*y=g//g=gcd(a,b);

令其一个解为(x0, y0)

则解空间可定义为(x0+k*b/g, y0-k*a/g) //k取任意整数

所以可知下一次见面为(x0+b/g, y0-a/g)

因此每两个相邻解x差值为b/g,因此要保证所求x对应青蛙第一次见面时间需令x%(b/g),若为负数则+b/g

代码中的l/d对应的就是b/g



0 0
原创粉丝点击