题435. 同余-acwing-222. 青蛙的约会


题435. 同余-acwing-222. 青蛙的约会


一、关于线性同余方程的求解综述

1.对线性同余方程的解释

ax ≡ c (mod b)表示关于x的解集,其中x需满足(a*x)%b=c。求解该问题等价于求解方程ax+by=c(或ax%b==c%b),其中只要x的集合能够被求出,那么y的集合也可以通过x求出。

2.求解线性同余方程的方法:扩展欧几里得算法
(1)关于扩展欧几里得算法:

定义:正如其名,它是欧几里得算法的扩展,在得到整数a,b的最大公约数(我们通过欧几里得算法,即辗转相除法求解a,b最大公约数)后,还希望得到整数x,y,使得ax+by=gcd(a,b)

  • 对于整数a>b,当b=0时,gcd(a,b)=a,此时x=1,y=0;(我们知道,欧几里得算法到最后是形参b=0,return a,即a就是等于gcd(a,b),此时又有ax+by=gcd(a,b),那么显然x得等与1,y=0)
  • 假设ax+by=gcd(a,b),有x,y的解为x1,y1,则ax1+by1=gcd(a,b),此为①式;
  • 由欧几里得算法可知,当b!=0时做的操作为gcd(b,a%b),即进入到的gcd的形参a=b,b=a%b,则可设bx2+(a%b)y2=gcd(b,a%b),此为②式;
  • 又由欧几里得算法可知,当b!=0时做的操作为gcd(b,a%b),则gcd(a,b)=gcd(b,a%b),则结合①②式可知ax1+by1=bx2+(a%b)y2;
  • 由于a%b=a-(a/b)*b(被除数a等于商a/b乘以除数b加上余数a%b,则余数a%b是等于被除数a减商a/b乘以除数b),则ax1+by1=bx2+(a-(a/b)*b)y2=ay2+bx2-(a/b)*by2,即ax1+by1==ay2+b(x2-(a/b)*y2),此为③式;
  • 由恒等定理可知,③式成立则x1=y2,y1=x2-(a/b)*y2 ④;
  • 这样我们就得到了x1,y1,即ax+by=c的一组解,x1,y1基于x2,y2;
  • 以上操作同样以递归方式实现,是建立在欧几里得递归写法之上,当最后b=0时,递归结束,gcd(a,b)被求出,开始返回。设正处于扩欧函数调用过程中,则x2,y2在递归过程中处于更深的一层递归,x1,y1由那个更深的一层递归调用结束后的赋值语句得到,当最浅的一层递归调用结束时,形参a正等于原线性同余方程中的a,而b亦是如此,则对应的x1,y1即为一组解;

(2)求解线性同余方程

1)方程有整数解的充要条件为gcd(a,b)|c,即c为gcd(a,b)的倍数
2)上述扩欧过程求解了x,y,而对于线性同余方程,我们只需要那个x就好了
3)若x0,y0为方程ax+by=c的一组解,则方程任意解可表示为x=x0+b’t,y=y0-a’t,t∈任意整数,a’=a/gcd(a,b),b’=b/gcd(a,b)
4)特别的,若gcd(a,b)=1,且x0,y0为方程ax+by=c的一组解,则方程任意解可表示为x=x0+bt,y=y0-at,t∈任意整数
5)对于一般的求解线性同余方程问题,往往被要求求出一个最小整数解,该值为x=x0(x0 % t + t)%t,其中t=b/gcd(a,b),对于 4)而言t=b

二、题目

在这里插入图片描述

三、题解


那么,对于扩展欧几里得算法求线性方程有解的条件是c%gcd(a,b)==0,即c是gcd(a,b)的倍数,对此即为(b-a)%gcd(m-n,L)==0,否则输出 Impossible。
由于扩展欧几里得求出的是ax+by=gcd(a,b)的x,y的解,因此还需两边同时乘一个倍数c/gcd(a,b)使得右边变成c,x=x*(c/gcd(a,b)),对此即为x=x*[(b-a)/gcd(m-n,L)]。
之后,求x的最小正整数解直接套t=b/gcd(a,b),ans=(x%t+t)%t即可
代码如下:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    ll d=ex_gcd(b,a%b,y,x);//这里直接交换x、y,方便计算
    y-=a/b*x;
    return d;
}

int main()
{
    ll a,b,m,n,L;
    cin>>a>>b>>m>>n>>L;
    ll x,y;
    ll d=ex_gcd(m-n,L,x,y);//a,b,x,y
    if((b-a)%d) puts("Impossible");
    else
    {
        x*=((b-a)/d);
        ll t=abs(L/d);
        cout<<(x%t+t)%t;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值