P1082 [NOIP2012 提高组] 同余方程

思路

一开始想的是用快速幂和费马小定理当做求逆元题目写,费马小定理:a^p-a\equiv1(modp) 要求a,p互质,且p为质数才能使用,于是采用扩展欧几里得求逆元。

扩展欧几里得求逆元

如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b),这便是扩展欧几里得的基本式子。

要想使用扩展欧几里得求逆元,需要将式子化为ax+by=gcd(a,b)的形式。我们需要考虑回溯到的边界,因为辗转相除的边界是a=gcd(a,b),因此这题也不例外,这题边界是a=1,b=0。因此我们可以得到边界条件if(b==0){a=1,b=0},回溯得到最初的表达式ax+by=1(其中x为我们所需要的答案)。该题推导如下:

模板代码:

void exgcd(LL a, LL b, LL &x, LL &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
        return;
    }
    exgcd(b, a % b, y, x);
    y -= (a / b) * x;
}

实际上在看这段代码的时候对于函数递归时的关系有些模糊,接下来口述:由上一层递归到该层的时候,例如由第四层递归到第三层,由上述推导的式子可得:x3=y4,y3=x4-(a/b)*y4

式子y -= (a / b) * x的意思为:第三层的y3=y3-(a/b)*x3,由于的时候,y3=x4,x3=y4,因此该层式子变形可得:y3=y3-(a/b)*x3。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return;
    }
    exgcd(b, a % b, y, x);
    y -= (a / b) * x;
}
int main()
{
    ll x, y, a, b;
    cin >> a >> b;
    exgcd(a, b, x, y);
    cout << (x % b + b) % b;
    return 0;
}

答案是最小正数,因此结尾还要x%b+b

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值