Day 25 - 同余与乘法逆元

1|0欧拉函数

1|1定义

欧拉函数(Euler's totient function),即 φ(n),表示的是小于等于 nn 互质的数的个数。

比如说 φ(1)=1

n 是质数的时候,显然有 φ(n)=n1

1|2性质

  • 欧拉函数是积性函数。

    即对任意满足 gcd(a,b)=1 的整数 a,b,有 φ(ab)=φ(a)φ(b)

    特别地,当 n 是奇数时 φ(2n)=φ(n)

    证明参见剩余系的复合。

  • n=dnφ(d)

    证明:

    利用莫比乌斯反演相关知识可以得出。

    也可以这样考虑:如果 gcd(k,n)=d,那么 gcd(kd,nd)=1,(k<n)

    如果我们设 f(x) 表示 gcd(k,n)=x 的数的个数,那么 n=i=1nf(i)

    根据上面的证明,我们发现,f(x)=φ(nx),从而 n=dnφ(nd)。注意到约数 dnd 具有对称性,所以上式化为 n=dnφ(d)

  • n=pk,其中 p 是质数,那么 φ(n)=pkpk1
    (根据定义可知)

  • 由唯一分解定理,设 n=i=1spiki,其中 pi 是质数,有 φ(n)=n×i=1spi1pi

    证明:

    • 引理:设 p 为任意质数,那么 φ(pk)=pk1×(p1)

      证明:显然对于从 1 到 pk 的所有数中,除了 pk1p 的倍数以外其它数都与 pk 互素,故 φ(pk)=pkpk1=pk1×(p1),证毕。

      接下来我们证明 φ(n)=n×i=1spi1pi。由唯一分解定理与 φ(x) 函数的积性

      φ(n)=i=1sφ(piki)=i=1s(pi1)×piki1=i=1spiki×(11pi)=n i=1s(11pi)

  • 对任意不全为 0 的整数 m,nφ(mn)φ(gcd(m,n))=φ(m)φ(n)gcd(m,n)

    可由上一条直接计算得出。

1|3实现

如果只要求一个数的欧拉函数值,那么直接根据定义质因数分解的同时求就好了。这个过程可以用 Pollard Rho 算法优化。

#include <cmath> int euler_phi(int n) { int m = int(sqrt(n + 0.5)); int ans = n; for (int i = 2; i <= m; i++) if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } if (n > 1) ans = ans / n * (n - 1); return ans; }

注:如果将上面的程序改成如下形式,会提升一点效率:

#include <cmath> int euler_phi(int n) { int ans = n; for (int i = 2; i * i <= n; i++) if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } if (n > 1) ans = ans / n * (n - 1); return ans; }

1|4欧拉定理

与欧拉函数紧密相关的一个定理就是欧拉定理。其描述如下:

gcd(a,m)=1,则 aφ(m)1(modm)

1|5扩展欧拉定理

当然也有扩展欧拉定理

ab{abmodφ(p),gcd(a,p)=1ab,gcd(a,p)1,b<φ(p)abmodφ(p)+φ(p),gcd(a,p)1,bφ(p)(modp)

2|0裴蜀定理

2|1定义

裴蜀定理,又称贝祖定理、贝祖等式。是一个关于最大公约数的定理。

其内容是:

a,b 是不全为零的整数,对任意整数 x,y,满足 gcd(a,b)ax+by,且存在整数 x,y, 使得 ax+by=gcd(a,b).

2|2证明

对于第一点

由于 gcd(a,b)a,gcd(a,b)b

所以 gcd(a,b)ax,gcd(a,b)by,其中 x,y 均为整数

因此 gcd(a,b)ax+by

对于第二点

  1. 若任何一个等于 0, 则 gcd(a,b)=a. 这时定理显然成立。

  2. a,b 不等于 0.

    由于 gcd(a,b)=gcd(a,b),

    不妨设 a,b 都大于 0ab,gcd(a,b)=d.

    ax+by=d, 两边同时除以 d, 可得 a1x+b1y=1, 其中 (a1,b1)=1.

    转证 a1x+b1y=1.

    我们先回顾一下辗转相除法是怎么做的,由 gcd(a,b)gcd(b,amodb) 我们把模出来的数据叫做 r 于是,有

    gcd(a1,b1)=gcd(b1,r1)=gcd(r1,r2)==(rn1,rn)=1

    把辗转相除法中的运算展开,做成带余数的除法,得

    a1=q1b1+r1(0r1<b1)b1=q2r1+r2(0r2<r1)r1=q3r2+r3(0r3<r2)rn3=qn1rn2+rn1rn2=qnrn1+rnrn1=qn+1rn

    不妨令辗转相除法在除到互质的时候退出则 rn=1 所以有(q 被换成了 x,为了符合最终形式)

    rn2=xnrn1+1

    1=rn2xnrn1

    由倒数第三个式子 rn1=rn3xn1rn2 代入上式,得

    1=(1+xnxn1)rn2xnrn3

    然后用同样的办法用它上面的等式逐个地消去 rn2,,r1,

    可证得 1=a1x+b1y.
    这样等于是一般式中 d=1 的情况。

2|3推广

1|0逆定理

a,b 是不全为零的整数,若 d>0a,b 的公因数,且存在整数 x,y, 使得 ax+by=d,则 d=gcd(a,b)

特殊地,设 a,b 是不全为零的整数,若存在整数 x,y, 使得 ax+by=1,则 a,b 互质。

1|0多个整数

裴蜀定理可以推广到 n 个整数的情形:设 a1,a2,,an 是不全为零的整数,则存在整数 x1,x2,,xn, 使得 a1x1+a2x2++anxn=gcd(a1,a2,,an)。其逆定理也成立:设 a1,a2,,an 是不全为零的整数,d>0a1,a2,,an 的公因数,若存在整数 x1,x2,,xn, 使得 a1x1+a2x2++anxn=d,则 d=gcd(a1,a2,,an)

2|4应用

给出 n 张卡片,分别有 lici。在一条无限长的纸带上,你可以选择花 ci 的钱来购买卡片 i,从此以后可以向左或向右跳 li 个单位。问你至少花多少元钱才能够跳到纸带上全部位置。若不行,输出 1

分析该问题,发现想要跳到每一个格子上,必须使得所选数 li1,,lik 通过数次相加或相减得出的绝对值为 1,也即存在整数 x1,,xn 使得 li1x1++likxk=1。由多个整数的裴蜀定理逆定理,这相当于从数组 l1,,ln 选择若干个数,满足它们的最大公因数为 1,同时要求代价和最小。

解法 1:我们可以转移思想,因为这些数互质,即为 0 号节点开始,每走一步求 gcd(节点号,下一个节点),同时记录代价(求边权),就成为了从 0 通过不断 gcd 最后变为 1 的最小代价。

由于:互质即为最大公因数为 1gcd(0,x)=x 这两个定理,可以证明该算法的正确。选择优先队列优化 Dijkstra 求解。

不过还有个问题,即为需要记录是否已经买过一个卡片,开数组标记由于数据范围达到 109 会超出内存限制,可以想到使用 unordered_map(比普通的 map 更快地访问各个元素,迭代效率较低)

解法 2:从数组 l1,,ln 选择若干个数,满足它们的最大公因数为 1,且代价和最小,由此可以想到 0-1 背包问题。

fi,j 表示考虑前 i 个数且最大公因数为 j 的最小代价,则有转移方程:

fi,j=mingcd(k,li)=jfi1,k+ci.

DP 后最终的总代价即为 fn,1

如同一般的 0-1 背包问题,可以用滚动数组优化,去掉第一维。而这里 300 个数可达的最大公因数 j 是很稀疏的,因此还可以使用 unordered_map 代替数组储存下标 j,优化内存并进一步减少枚举量。

实际上,这里解法 1 建出的图便是解法 2 中动态规划的状态转移图,解法 2 相当于用动态规划求有向无环图的最短路,因此解法 1 和解法 2 是等价的。但解法 2 无需储存全图,同时 DP 的时间复杂度为 O(n+m),相比 Dijkstra 算法更低,因此解法 2 在时间和空间上更优。

2|5进一步结论

对自然数 ab 和整数 nab 互素,考察不定方程:

ax+by=n

其中 x 和 y 为自然数。如果方程有解,称 n 可以被 a、b 表示。

C=abab。由 a 与 b 互素,C 必然为奇数。则有结论:

对任意的整数 n,n 与 Cn 中有且仅有一个可以被表示。

即:可表示的数与不可表示的数在区间 [0,C] 对称(关于 C 的一半对称)。0 可被表示,C 不可被表示;负数不可被表示,大于 C 的数可被表示。

1|0证明

由于 a、b 互素,因此原方程有整数解。设解为:

{x=x0+bty=y0at

其中 t 为整数。取适当的 t,使得 y 位于 0 到 a1 之间。这只需在 y0 上加上或减去若干个 a,即可得到这样的 t。

第一步:证明大于 C 的数都可以被表示。当 n 大于 C 时:

ax=nby>ababbyababb(a1)=a

于是 x 也是非负整数。

第二步:证明 C 不可被表示,进而 n 与 Cn 不可能都被表示。

反证法。若 ax+by=abab 有非负整数解 x、y,则:

ab=a(x+1)+b(y+1)

由于 a 与 b 互素,所以 a 整除 y+1,b 整除 x+1,a 不超过 y+1,b 不超过 x+1。于是有:

ab=a(x+1)+b(y+1)ab+ab=2ab

矛盾!第二步证完。

第三步:证明如果 n 不可被表示,则 Cn 可被表示。

由上可知,若 n 不可被表示,由于上述方程中已规定 y 在 0 到 a1 之间,则 x 为负。所以:

ababaxby=a(x1)+b(a1y)

显然 x1a1y 均非负,于是 Cn 可被表示。

1|0几何意义

重新观察方程 ax+by=n,将它看成一条直线。直线与两坐标轴在第一象限围成三角形。

n<ab 的时候,这个直线在第一象限,至多只能通过一个整点。

根据上述讨论:当 n 可以被表示的时候,直线恰好经过一个整点;当 n 不可以被表示的时候,直线不经过整点(在第一象限)。

这结论也可以理解为:作三角形 (0,0)(b,0)(0,a)。随着 n 从 0 不断增加,直线向右上方平移,整点会一个一个地通过直线,直到最后才撞上两个整点。

因此,小于等于 n 的能被表示的非负整数的数量,恰好就是直线 ax+by=n(含)与两坐标轴(含)在第一象限围成三角形覆盖的整点个数。

1|0另一种解释

考虑模 b 意义下每个剩余系中最小能被表示的值是多少——大于他们的可以通过增加若干个 b 得到。

观察原方程,a 的若干倍数 0,a,,(b1)a(modb) 意义下互不相同。这些数恰好是这些最小值。那么当 n<ab 时,小于等于 n 的能被表示的非负整数的数量是:

i=0[na][niab]

这是一个非常经典的直线下整点问题,恰好是这条直线:

y=abx+nb

ax+by=n

使用类欧几里得算法可以在 O(logmax(a,b)) 的时间内求解。因此我们得到了计算小于等于 n 的能被表示的非负整数的数量的工具。

1|0题目

P3951 NOIP2017 提高组 小凯的疑惑/蓝桥杯 2013 省 买不到的数目

3|0费马小定理 & 欧拉定理

3|1费马小定理

1|0定义

p 为素数,gcd(a,p)=1,则 ap11(modp)

另一个形式:对于任意整数 a,有 apa(modp)

1|0证明

设一个质数为 p,我们取一个不为 p 倍数的数 a

构造一个序列:A={1,2,3,p1},这个序列有着这样一个性质:

i=1p1 Aii=1p1(Ai×a)(modp)

证明:

(Ai,p)=1,(Ai×a,p)=1

又因为每一个 Ai×a(modp) 都是独一无二的,且 Ai×a(modp)<p

得证(每一个 Ai×a 都对应了一个 Ai

f=(p1)!, 则 fa×A1×a×A2×a×A3×Ap1(modp)

ap1×ff(modp)ap11(modp)

证毕。

也可用归纳法证明:

显然 1p1(modp),假设 apa(modp) 成立,那么通过二项式定理有

(a+1)p=ap+(p1)ap1+(p2)ap2++(pp1)a+1

因为 (pk)=p(p1)(pk+1)k! 对于 1kp1 成立,在模 p 意义下 (p1)(p2)(pp1)0(modp),那么 (a+1)pap+1(modp),将 apa(modp) 带入得 (a+1)pa+1(modp) 得证。

3|2欧拉定理

在了解欧拉定理(Euler's theorem)之前,请先了解欧拉函数。定理内容如下:

1|0定义

gcd(a,m)=1,则 aφ(m)1(modm)

1|0证明

实际上这个证明过程跟上文费马小定理的证明过程是非常相似的:构造一个与 m 互质的数列,再进行操作。

r1,r2,,rφ(m) 为模 m 意义下的一个简化剩余系,则 ar1,ar2,,arφ(m) 也为模 m 意义下的一个简化剩余系。所以 r1r2rφ(m)ar1ar2arφ(m)aφ(m)r1r2rφ(m)(modm),可约去 r1r2rφ(m),即得 aφ(m)1(modm)

m 为素数时,由于 φ(m)=m1,代入欧拉定理可立即得到费马小定理。

3|3扩展欧拉定理

1|0定义

ab{abmodφ(m),gcd(a,m)=1,ab,gcd(a,m)1,b<φ(m),a(bmodφ(m))+φ(m),gcd(a,m)1,bφ(m).(modm)

1|0解释

读者可能对第二行产生疑问,这一行表达的意思是:如果 b<φ(m) 的话,就不能降幂了。

主要是因为题目中 m 不会太大,而如果 b<φ(m),自然复杂度是可以接受的。而如果 bφ(m) 的话,复杂度可能就超出预期了,这个时候我们才需要降幂来降低复杂度。

1|0证明

1|0直观理解

fermat1

需要知道的是,在 (modm) 的条件下,abmodm 的取值范围一定在 [0,m),而 aimodm=(ai1modm)×amodm,那么对于任意一个数 a,那么很容易就能知道它的 后继,在有限的空间内这一定会形成一个循环。

在扩展欧拉定理中,循环分为纯循环和混循环。其中纯循环中不存在节点有两个前驱,而混循环则反之。而 aimodn 形成的序列可以是一个混循环,那么只需要知道循环节的长度,和前面那一小段未进入循环节的长度,就可以根据这个性质来进行降幂了。

值得注意的是,无论是费马小定理,还是(扩展)欧拉定理,一个很重要的应用就是降幂,从而将不可能的表达式化为可能。

1|0形式证明

证明转载自 synapse7,并进行了一些整理。

  1. 命题a 的从 0 次,1 次到 b 次幂模 m 构成的序列中,存在 rs,使得前 r 个数(即从 a0modmar1modm)互不相同,从第 r 个数开始,每 s 个数就循环一次。

    证明

    • 由鸽巢定理易证。

      我们把 r 称为 a 幂次模 m 的循环起始点,s 称为循环长度。(注意:r 可以为 0

      用公式表述为:ir,aiai+s(modm)

  2. 命题a 为素数的情况,该式成立。

    证明

    • 若模 m 不能被 a 整除,而因为 a 是一个素数,那么 gcd(a,m)=1 成立,根据欧拉定理,容易证明该式成立。

    • 若模 m 能被 a 整除,那么存在 rm 使得 m=arm,且 gcd(a,m)=1 成立。所以根据欧拉定理有 aφ(m)1(modm)

      又由于 gcd(ar,m)=1,所以根据欧拉函数的求值规则,容易得到:φ(m)=φ(m)×(a1)ar1,即我们有:φ(m)φ(m)

      所以 aφ(m)1(modm),φ(m)φ(m)aφ(m)1(modm),即 aφ(m)=km+1,两边同时乘以 ar,得 ar+φ(m)=km+ar(因为 m=arm

      所以对于 m 中素因子 a 的次数 r 满足:arar+φ(m)(modm)。我们可以简单变换形式,得到 推论

      b>rabar+((br)modφ(m))(modm)

      又由于 m=arm,所以 φ(m)=φ(ar)φ(m)φ(ar)=ar1(a1)r(tips:a 是素数,最小是 2,而 r1)。

      所以因为 φ(m)r,故有:

      arar+φ(m)armodφ(m)+φ(m)(modm)

      所以

      abar+(br)modφ(m)armodφ(m)+φ(m)+(br)modφ(m)aφ(m)+bmodφ(m)(modm)

      ababmodφ(m)+φ(m)(modm)

  3. 命题a 为素数的幂的情况,该式成立。

    证明

    • 不妨令 a=pk,是否依然有 r,arar+φ(m)(modm)

      答案是肯定的,由命题 1 可知存在 s 使得 as1(modm),所以 plcm(s,k)1(modm),所以令 s=sgcd(s,k) 时,我们能有 psk1(modm)

      此时有关系:sssφ(m),且 r=rkrφ(m),由 r,sφ(m) 的关系,依然可以得到 ababmodφ(m)+φ(m)(modm)

  4. 命题a 为合数的情况,该式成立。

    证明

    • 只证 a 拆成两个素数的幂的情况,大于两个的用数学归纳法可证。

      a=a1a2,其中 ai=piki,而 ai 的循环长度为 si

      slcm(s1,s2),由于 s1φ(m),s2φ(m),那么 lcm(s1,s2)φ(m),所以 sφ(m)r=max(riki)max(ri)φ(m)

      r,sφ(m) 的关系,依然可以得到 ababmodφ(m)+φ(m)(modm)

      证毕。

3|4习题

  1. SPOJ #4141 "Euler Totient Function"[Difficulty: CakeWalk]
  2. UVa #10179 "Irreducible Basic Fractions"[Difficulty: Easy]
  3. UVa #10299 "Relatives"[Difficulty: Easy]
  4. UVa #11327 "Enumerating Rational Numbers"[Difficulty: Medium]
  5. TIMUS #1673 "Admission to Exam"[Difficulty: High]

4|0乘法逆元

4|1定义

如果一个线性同余方程 ax1(modb),则 x 称为 amodb 的逆元,记作 a1

4|2如何求逆元

1|0扩展欧几里得法

实现:

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

扩展欧几里得法和求解线性同余方程是一个原理,在这里不展开解释。

1|0快速幂法

1|0证明

因为 ax1(modb)

所以 axab1(modb)(根据费马小定理);

所以 xab2(modb)

然后我们就可以用快速幂来求了。

实现:

int qpow(long long a, int b) { int ans = 1; a = (a % p + p) % p; for (; b; b >>= 1) { if (b & 1) ans = (a * ans) % p; a = (a * a) % p; } return ans; }

注意:快速幂法使用了费马小定理,要求 b 是一个素数;而扩展欧几里得法只要求 gcd(a,b)=1

1|0线性求逆元

求出 1,2,,n 中每个数关于 p 的逆元。

如果对于每个数进行单次求解,以上两种方法就显得慢了,很有可能超时,所以下面来讲一下如何线性(O(n))求逆元。

首先,很显然的 111(modp)

证明:

对于 pZ,有 1×11(modp) 恒成立,故在 p1 的逆元是 1,而这是推算出其他情况的基础。

其次对于递归情况 i1,我们令 k=pij=pmodi,有 p=ki+j。再放到 modp 意义下就会得到:ki+j0(modp)

两边同时乘 i1×j1

kj1+i10(modp)

i1kj1(modp)

再带入 j=pmodi,有 p=ki+j,有:

i1pi(pmodi)1(modp)

我们注意到 pmodi<i,而在迭代中我们完全可以假设我们已经知道了所有的模 p 下的逆元 j1,j<i

故我们就可以推出逆元,利用递归的形式,而使用迭代实现:

i1{1,if i=1,pi(pmodi)1,otherwise.(modp)

实现:

inv[1] = 1; for (int i = 2; i <= n; ++i) { inv[i] = (long long)(p - p / i) * inv[p % i] % p; }

使用 ppi 来防止出现负数。

另外我们注意到我们没有对 inv[0] 进行定义却可能会使用它:当 i|p 成立时,我们在代码中会访问 inv[p % i],也就是 inv[0],这是因为当 i|p 时不存在 i 的逆元 i1。线性同余方程中指出,如果 ip 不互素时不存在相应的逆元(当一般而言我们会使用一个大素数,比如 109+7 来确保它有着有效的逆元)。因此需要指出的是:如果没有相应的逆元的时候,inv[i] 的值是未定义的。

另外,根据线性求逆元方法的式子:i1kj1(modp)

递归求解 j1, 直到 j=1 返回 1

中间优化可以加入一个记忆化来避免多次递归导致的重复,这样求 1,2,,n 中所有数的逆元的时间复杂度仍是 O(n)

注意:如果用以上给出的式子递归进行单个数的逆元求解,目前已知的时间复杂度的上界为 O(n13),具体请看 知乎讨论。算法竞赛中更好地求单个数的逆元的方法有扩展欧几里得法和快速幂法。

1|0线性求任意 n 个数的逆元

上面的方法只能求 1n 的逆元,如果需要求任意给定 n 个数(1ai<p)的逆元,就需要下面的方法:

首先计算 n 个数的前缀积,记为 si,然后使用快速幂或扩展欧几里得法计算 sn 的逆元,记为 svn

因为 svnn 个数的积的逆元,所以当我们把它乘上 an 时,就会和 an 的逆元抵消,于是就得到了 a1an1 的积逆元,记为 svn1

同理我们可以依次计算出所有的 svi,于是 ai1 就可以用 si1×svi 求得。

所以我们就在 O(n+logp) 的时间内计算出了 n 个数的逆元。

实现:

s[0] = 1; for (int i = 1; i <= n; ++i) s[i] = s[i - 1] * a[i] % p; sv[n] = qpow(s[n], p - 2); // 当然这里也可以用 exgcd 来求逆元,视个人喜好而定. for (int i = n; i >= 1; --i) sv[i - 1] = sv[i] * a[i] % p; for (int i = 1; i <= n; ++i) inv[i] = sv[i] * s[i - 1] % p;

4|3逆元练习题

乘法逆元

乘法逆元 2

「NOIP2012」同余方程

「AHOI2005」洗牌

「SDOI2016」排列计数

5|0线性同余方程

5|1定义

形如

axb(modn)

的方程称为 线性同余方程Linear Congruence Equation)。其中,abn 为给定整数,x 为未知数。需要从区间 [0,n1] 中求解 x,当解不唯一时需要求出全体解。

5|2用逆元求解

首先考虑简单的情况,当 an 互素(coprimerelatively prime)时,即 gcd(a,n)=1

此时可以计算 a 的逆元,并将方程的两边乘以 a 的逆元,可以得到唯一解。

1|0证明

xba1(modn)

接下来考虑 an 不互素(not coprime),即 gcd(a,n)1 的情况。此时不一定有解。例如,2x1(mod4) 没有解。

g=gcd(a,n),即 an 的最大公约数,其中 an 在本例中大于 1。

b 不能被 g 整除时无解。此时,对于任意的 x,方程 axb(modn) 的左侧始终可被 g 整除,而右侧不可被 g 整除,因此无解。

如果 g 整除 b,则通过将方程两边 abn 除以 g,得到一个新的方程:

axb(modn)

其中 an 已经互素,这种情形已经解决,于是得到 x 作为 x 的解。

很明显,x 也将是原始方程的解。这不是唯一的解。可以看出,原始方程有如下 g 个解:

xi(x+in)(modn)for i=0g1

总之,线性同余方程的 解的数量 等于 g=gcd(a,n) 或等于 0

5|3用扩展欧几里得算法求解

根据以下两个定理,可以求出线性同余方程 axb(modn) 的解。

定理 1:线性同余方程 axb(modn) 可以改写为如下线性不定方程:

ax+nk=b

其中 xk 是未知数。这两个方程是等价的,有整数解的充要条件为 gcd(a,n)b

应用扩展欧几里德算法可以求解该线性不定方程。根据定理 1,对于线性不定方程 ax+nk=b,可以先用扩展欧几里得算法求出一组 x0,k0,也就是 ax0+nk0=gcd(a,n),然后两边同时除以 gcd(a,n),再乘 b。就得到了方程

abgcd(a,n)x0+nbgcd(a,n)k0=b

于是找到方程的一个解。

定理 2:若 gcd(a,n)=1,且 x0k0 为方程 ax+nk=b 的一组解,则该方程的任意解可表示为:

x=x0+nt

k=k0at

并且对任意整数 t 都成立。

根据定理 2,可以从已求出的一个解,求出方程的所有解。实际问题中,往往要求出一个最小整数解,也就是一个特解

x=(xmodt+t)modt

其中有

t=ngcd(a,n)

如果仔细考虑,用扩展欧几里得算法求解与用逆元求解,两种方法是等价的。

1|0实现

代码实现:

int ex_gcd(int a, int b, int& x, int& y) { if (b == 0) { x = 1; y = 0; return a; } int d = ex_gcd(b, a % b, x, y); int temp = x; x = y; y = temp - a / b * y; return d; } bool liEu(int a, int b, int c, int& x, int& y) { int d = ex_gcd(a, b, x, y); if (c % d != 0) return 0; int k = c / d; x *= k; y *= k; return 1; }

本页面主要译自博文 Модульное линейное уравнение первого порядка 与其英文翻译版 Linear Congruence Equation。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。

1|0习题

「NOIP2012」同余方程


__EOF__

本文作者So_noSlack
本文链接https://www.cnblogs.com/So-noSlack/p/18335879.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   So_noSlack  阅读(63)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示