思路
一开始想的是用快速幂和费马小定理当做求逆元题目写,费马小定理:a^p-a1(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