跳至主要內容

GCD、EXGCD

KSJ大约 2 分钟

GCD、EXGCD

GCD

gcd(a,b)=gcd(b,a%b)

证明:

a=bq+r=bq+a%ba%b=abqd=gcd(a,b),d|a,d|bd|a%bd=(b,a%b)

得证

代码

int gcd(a,b) {
  if(!b)return a;
  return (b,a%b);
}

EXGCD

原理

裴蜀定理ax+by=gcd(a,b)

以及gcd(a,b)=gcd(b,a%b)

带入有ax1+by1=bx2+a%by2=bx2+(abq)y2

对比系数有x1=y2,y2=x2aby2

注意到 ax + 0y=gcd(a,0)=a 得x=1,y=0

void exgcd(a,b,int& x,int& y){
  if(!b){
    x=1,y=0;
    return;
  }
  exgcd(b,a%b,y,x); // 求解 gcd(b,a%b)的系数y,x
  // x=y_2 已经自动赋值了
  y = y - a/b *x; // x_2 - a/b y_2
}

gcd(a,b)=1,b,x=a1(modp)

费马小定理

ap1=1(modp)

aap2=1(modp)

a1=ap2

inv[1]=1;
for(i in 1... ) {
  inv[i]=(p-p/i)*inv[p%i] % p;
}

递推办法

inv(i)=(pp/i)inv(p%i)%p

inv(1)=1

数学推导

我们需要证明 inv(i)=(pp/i)inv(p%i)%p

inv(i)i 在模 p 意义下的逆元,即 iinv(i)1(modp)

根据模运算的性质,有:

iinv(i)1(modp)

我们可以将 i 表示为 pp%i 的线性组合:

i=p(p%i)pi

inv(p%i)p%i 在模 p 意义下的逆元,即:

(p%i)inv(p%i)1(modp)

i 的表达式代入 iinv(i)1(modp)

(p(p%i)pi)inv(i)1(modp)

展开并整理:

pinv(i)(p%i)piinv(i)1(modp)

由于 pinv(i)0(modp),因此:

(p%i)piinv(i)1(modp)

两边同时乘以 1

(p%i)piinv(i)1(modp)

inv(p%i) 代入上式:

(p%i)inv(p%i)1(modp)

因此:

piinv(i)inv(p%i)(modp)

所以:

inv(i)(pp/i)inv(p%i)(modp)

即:

inv(i)=(pp/i)inv(p%i)%p

得证。