扩展欧几里得详解 NOIP2012同余方程 青蛙的约会

鼓起了很大勇气决定发表这篇文章但是没想到写完一遍忘保存gg了 (捂脸哭) anyway 现在我还是重新开始了
扩展欧几里得这个算法是计算ax+by=c 关于(x,y)的整数解的
首先 如果(x,y)有解 必须是当且仅当c是gcd(a,b)的倍数
证明:一、:如果有整数解,则c是p的倍数。
令p=gcd(a,b)
a=aa*p
b=bb*p
则gcd(aa,bb)=1
c=ax+by=p*(aa*x+bb*y) 那么c显然是p的倍数
二、如果c是p的倍数,则ax+by=c有整数解。(在证明这个的同时也是拓展欧几里得的过程)
①用欧几里得算法计算gcd(a,b)时最后调用的一定是gcd(p,0),对于(p,0)来说是存在对应的(x,y)使得p*x+0*y=c成立的,只要让x=c/p,y取任意数即可;
②欧几里得算法的核心是把(a,b)辗转为(b,a mod b),假设(b,a mod b)存在对应的(x1,y1)使得 b*x1+(a mod b)*y1=c,根据:

  ax+by=b*x1+(a mod b)*y1 
       =b*x1+(a-[a/b]*b)*y1 
       =a*y1+b*(x1-[a/b]*y1)
  x=y1,y=x1-[a/b]*y1

即存在整数解x,y满足ax+by=c
x=y1 y=x1-[a/b]*y1
我们得出这个结论后 只要在gcd递归的过程中用 上一次递归出来的x1,y1 来替换现在的
x=y1 y=x1-[a/b]*y1

void gcd(long long a,long long b)
{long long o; 
  if (b==0)
  { x=c/a;y=0;
    return;
  }
  gcd(b,a%b);
  o=x;x=y;y=o-a/b*y;
}

ax+by=c有无穷组解,扩展欧几里得算法计算出来的解是其中一个特解(x0,y0),我们完全可以在递归出口处任意修改y的值来获得其他特解。
假如我们把方程的所有解按x的值从小到大排序,特解(x0,y0)的下一组解可以表示为(x0+d1,y0+d2),其中d1是符合条件的最小的正整数,则满足:a*(x0+d1)+b*(y0,d2)=c,由于ax+by=c,所以a*d1+b*d2=0。即:

(https://img-blog.csdn.net/20161101155044390)

所以如果要最小正整数解
我们只需要把求出来的特解 x x=(x+mod)%mod就行了 mod=b/gcd(a,b)

pku 1061青蛙的约会

题意:有两只青蛙,一只在坐标x,另一直在坐标y,青蛙x一次跳跃可以前进m单位距离,青蛙y一次跳跃可以前进n单位的距离,两青蛙都在同一纬度,该纬度长度为L。两只青蛙同方向同时跳,问最少跳多少次,它们才可以相遇,如果不能相遇,输出impossible

假设跳了T次以后,青蛙1的坐标x+m*T,青蛙2的坐标y+n*T。它们能够相遇的情况为
(x+m*T)-(y+n*T)=P*L
(n-m)*T+P*L=x-y
设a=(n-m),b=L,c=x-y,T=x,P=y
那么 ax+by=c

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
long long x,y,u,v,n,m,l,g;
void gcd(long long a,long long b)
{long long o; 
  if (b==0)
  { x=(u-v)/a;y=0;
    g=a;return;
  }
  gcd(b,a%b);
  o=x;x=y;y=o-a/b*y;
}
int main()
{scanf("%lld%lld%lld%lld%lld",&u,&v,&m,&n,&l);
  gcd(n-m,l);
  l=l/g;
  if ((u-v)%g!=0) printf("Impossible");
  else printf("%lld",(x%l+l)%l);
} 

NOIP2012 同余方程

求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解。
ax mod b=1 mod b
ax+by=1 这里c=1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
int x,y,a,b;
void gcd(int a,int b)
{int t; 
  if (b==0)
  { x=1;
    y=0;
    return;
  }
  gcd(b,a%b);
  t=x;x=y;y=t-(a/b)*y;
}
int main()
{ scanf("%d%d",&a,&b);
  gcd(a,b);
  printf("%d",(x%b+b)%b);
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值