1.逆
求解一般形式的同余方程 a x ≡ b ( m o d m ) ax\equiv b(\bmod m) ax≡b(modm),需要用到逆(Inverse)。
逆的概念
给定整数 a a a,且满足 gcd ( a , m ) = 1 \gcd(a,m)=1 gcd(a,m)=1,称 a x ≡ 1 ( m o d m ) ax\equiv1(\bmod m) ax≡1(modm) 的一个解为 a a a 模 m m m 的逆,记为 a − 1 a^{-1} a−1。
例如, 8 x ≡ 1 ( m o d 31 ) 8x\equiv1(\bmod 31) 8x≡1(mod31),有一个解是 x = 4 x = 4 x=4, 4 4 4是 8 8 8 模 31 31 31 的逆。所有解,如 35 , 66 35,66 35,66 等,都是 8 8 8模 31 31 31 的逆。
可以借助丢番图方程理解逆的概念, 8 x ≡ 1 ( m o d 31 ) 8x\equiv1(\bmod 31) 8x≡1(mod31) 即方程 8 x + 31 y = 1 , x = 4 8x + 31y=1,x = 4 8x+31y=1,x=4 是 8 8 8 模 31 31 31 的逆, 4 × 8 − 1 4\times8 - 1 4×8−1 能整除 31 31 31。
从逆的要求 gcd ( a , m ) = 1 \gcd(a,m)=1 gcd(a,m)=1可以看出,做竞赛题时,模 m m m 最好是一个大于 a a a 的素数,才能保证 gcd ( a , m ) = 1 \gcd(a,m)=1 gcd(a,m)=1。
2.求逆
有多种方法可以求逆。
1)扩展欧几里得算法求单个逆
下面的例题是求逆,即求解同余方程 a x ≡ 1 ( m o d m ) ax\equiv1(\bmod m) ax≡1(modm)。
例题1 同余方程(求逆)(洛谷 P1082)
问题描述:求关于 x 的同余方程 a x ≡ 1 ( m o d m ax\equiv1(\bmod m ax≡1(modm) 的最小正整数解。 2 ≤ a , m ≤ 2000000000 2\leq a,m\leq2000000000 2≤a,m≤2000000000。
a x ≡ 1 ( m o d m ) ax\equiv1(\bmod m) ax≡1(modm),即丢番图方程 a x + m y = 1 ax + my = 1 ax+my=1,先用扩展欧几里得算法求出 a x + m y = 1 ax+my = 1 ax+my=1的一个特解 x 0 x_0 x0,通解是 x = x 0 + m n x = x_0+mn x=x0+mn。然后通过取模操作计算最小整数解 ( x 0 m o d m + m ) m o d m (x_0\bmod m + m)\bmod m (x0modm+m)modm,因为 m > 0 m>0 m>0,可以保证结果是正整数。
long long mod_inverse(long long a, long long m){ //求逆
long long x, y;
extend_gcd(a, m, x, y);
return (x % m + m) % m; //保证返回最小正整数
}
int main(){
long long a, m; cin >> a >> m;
cout << mod_inverse(a, m);
return 0;
}
下面给出一道类似的习题。
例题2 C looooops(poj 2115)
问题描述:C 语言的循环语句 f o r ( v a r i a b l e = A ; v a r i a b l e ! = B ; v a r i a b l e + = C ) for(variable = A; variable != B; variable += C) for(variable=A;variable!=B;variable+=C),当 v a r i a b l e = = B variable == B variable==B 时结束循环。A、B、C 的数据类型的长度是 k k k 位,也就是说,当 v a r i a b l e variable variable 超过 k k k 位时,只保留 k k k 位,相当于对 2 k 2^k 2k取模。给出 A 、 B 、 C A、B、C A、B、C 和 k k k,判断循环是否能在有限次内结束,若能结束,则输出循环次数。
设循环次数为 x x x, ( A + C x ) m o d 2 k = B (A + Cx)\bmod{2^k}=B (A+Cx)mod2k=B,这是同余方程 C