CH3301 exgcd
题面
CH3301题面
思路
很清楚了就是
a
x
≡
1
(
m
o
d
b
)
ax\equiv 1(mod\space b)
ax≡1(mod b),根据同余的定义,那么就有
a
x
−
1
≡
0
(
m
o
d
b
)
ax-1 \equiv0(mod\space b)
ax−1≡0(mod b),又可以得到
b
∣
a
x
−
1
b\mid ax-1
b∣ax−1,不妨令这个倍数为-y,对应的Eucild方程就是
(
a
x
+
b
y
=
1
)
(ax+by=1)
(ax+by=1)(如果等于号的右边不是1(假如是p),可以先通过exgcd算出等于号右边改为gcd的解,如果gcd不能整除p,该方程无解,有解时把解乘以p/gcd就是所求方程的解,很好理解吧(把等于gcd的方程两边乘上这个倍数,就能找到其与右边等于p的方程的解得关系了)),找到x的集合就行了,由于整除1的数只有1,那么只能
g
c
d
(
a
,
b
)
=
1
gcd(a,b) = 1
gcd(a,b)=1,用exgcd求出一个解
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0),那么通解集合就是(尝试代入试一下,真的记不住)
x
=
x
0
+
k
∗
b
,
y
=
y
0
−
k
∗
a
(
k
∈
Z
)
x = x_0+k*b,\space y= y_0-k*a\space (k \in Z)
x=x0+k∗b, y=y0−k∗a (k∈Z) 也就是所有模b同余
x
0
x_0
x0的整数,通过取模操作把解得范围移动到1-b之间,就得到了最小正整数解
注意事项
1)把包括负数在内的数调到最小正整数范围的公式
a
=
(
(
a
m
o
d
b
)
+
b
)
m
o
d
b
(1)
a = ((a\space mod\space b)+b)mod\space b \tag{1}
a=((a mod b)+b)mod b(1)
2)exgcd()在递归过程中,由于使用的是传引用(这里等效于全局变量),先把这一层栈的结果赋给一个值(而不是直接return),然后依次改变x和y,然后再return,这种调用到最底层返回值,并在传值到最顶层(经过逐层运算)返回值的方法不常见,相当于一次顺便做了多次的递归,值得学习
3)这里输出的时候那个(long long)可以不加(是因为巧了),按理来说如果b取2e9,x又刚好大于2e8就超了
代码
#include <iostream>
using namespace std;
typedef long long ll;
int x,y;
int exgcd(int a,int b,int &x,int &y)
{
if(!b) {x = 1;y = 0;return a;}
else
{
int d = exgcd(b,a%b,x,y);
int z = x;x = y;y = z-(a/b)*y;
return d;
}
}
int main()
{
int a ,b;
cin >>a >> b;
int ans = exgcd(a,b,x,y);
cout << (((ll)x%b)+b)%b<<endl;
//eliminate the minus one
return 0;
}