【解析】【模板】扩展欧几里得

noip2012 同余方程

题目描述

求关于 x 的同余方程 ax ≡ 1 (mod b) 的最小正整数解。

输入

输入只有一行,包含两个正整数 a ,b ,用一个空格隔开。

输出

输出只有一行,包含一个正整数 x 0 ,即最小正整数解。输入数据保证一定有解。
好吧这道水题各位神犇应该都会。。下面是蒟蒻的自嗨时间#


首先,同余的概念:a同余b(mod c)代表a-b可以整除c(a-b|c),即存在一个数k,使kc=(a-b)。

这道题转化一下,就相当于(ax-1)=y*b.(y是另一个参数)ax-by=1。b的系数没什么关系,就写成ax+by=1.

可以使用扩展欧几里得算法求解。

什么是扩展欧几里得算法呢?我们考虑一个更全面的问题,ax+by=c。这是一个二元一次方程,有无数组解。但是我们如果想要求它的整数解:



定理:对于ax+by=c,若c不能整除gcd(a,b),则方程无整数解。

证明:设gcd(a,b)=t。显然,a|t,则ax|t,同理by|t,则ax+by|t(左面整除c)。若c不整除t,那么无论xy为何值,均不能使左边等于c。


我们已经证明了c|gcd(a,b),那么我们可以将ab分别除以gcd(a,b)。就可以转化为ax+by=1的形式了。【就是本题的形式】

接下来观察这样两个式子:ax+by=1,bx+a%by=1.

有没有发现特别像gcd(a,b)=gcd(b,a%b)?(不会的话百度一下辗转相除法)

事实上,这两个式子的系数(a,b)的gcd相同。而第一个式子系数gcd=1,所以第二个式子gcd也是1,第二个式子必有整数解。而其实,第二个式子可以作为第一个的下一个状态,回溯处第一个式子。下面的推导请跟住:万一考试忘了,可以自己搞出来


ax+by=1

观察bx+(a%b)y=1

可化为bx+(a-a/b*b)y=1.(计算机里的除法向下取整)(a%b=b-(a/b*b))

展开:bx+ay-a/b*by=1

按照系数整理:ay+b(x-a/b*y)=1.

于是我们发现,这个式子和原来的形式相同。可以通过另x=y,y=x-a/b*y,求解新的ax+by=1。

可以使用递归来写。


那么递归出口是什么呢?根据辗转相除法,b最后一定是0,a最后就是gcd(a,b),即1。

所以最后,b=0,a=1.将这个值带入,得到x=1,y为任意值。为方便,y取0。


由于这是一个递归过程,最后的x即为一组解。

然而本题要求最小整数解。生活中也没人会无聊到让你去写一个老大老大乱七八糟的解。。。

如何求最小整数解?


我们现在得到了一组解:x0,y0.如果我们改变x0,y0的值,还要使得式子成立,那么只能x0+b或-b,与此同时y0-a或+

a。这样,a(x0-b)+b(y0-a)展开后正好消去a*b这一项。


所以求最小正整数解,我们只要把求出的一个解x,%b。x可能是负数,要+b。若非负加完可能不是最小,再%b。

下面是代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
long long a,b,x,y;
void exgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0){x=1;y=0;}
    exgcd(b,a%b,x,y);
    long long t=x;
    x=y;
	y=t-a/b*y;
}
int main()
{
   cin>>a>>b;
   exgcd(a,b,x,y);
   cout<<(x%b+b)%b<<endl;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值