基础数学

扩展欧几里得

在讲欧几里得之前我想写说gcd,因为在我学习exgcd时候没有深刻理解递归gcd导致看了很长时间的exgcd的都代码才懂

辗转相除

int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}

​ 在辗转相除的应用中我们可以知道的是gcd(a,b)=gcd(b,a%b);然后层层递归求得当b=0时候的解

贝祖定理

当a,b∈Z,那么一定存在x,y∈Z使得ax+by=gcd(a,b);

现在给出一个方程ax+by=m,如果此方程有解,那么m一定是gcd的若干倍(用来判断这样的式子是否有解)

特例:

​ ax+by=1,此时gcd=1

扩展欧几里得

板子:

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

要注意的是这个板子是简化版直接替换了x,y的位置

完整版:

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

逆元

为什么要求逆元?

因为除法求余是错误的!- (a÷b)%c=(a%c÷b%c)%*c*

exgcd求逆元

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

要注意的是求出来的逆元可能是‘负值’,还有后面的处理

	ll x=0,y=0;exgcd(b,mod,x,y);
	if(x<0) x+=mod;
	ll ans=(n*((x%mod+mod)%mod))%mod;

这里的x就是a%b的逆元,y是b%a的逆元

注意

​ 要理解引用的用法

费马小定理

快速幂求逆元-求a的p-2次方

前提:

​ gcd(a,p)=1且p为质数--具体不清楚以后再来补这个坑

递推求阶乘逆元-未理解直接抄的

我们经常会用到阶乘的逆元,我们可以考虑用费马小定理先求出最大那个阶乘的逆元,然后再往回推,直接看代码再解释。

void init() {
	fact[0] = 1;
	for (int i = 1; i < maxn; i++) {
		fact[i] = fact[i - 1] * i %mod;
	}
	inv[maxn - 1] = power(fact[maxn - 1], mod - 2);
	for (int i = maxn - 2; i >= 0; i--) {
		inv[i] = inv[i + 1] * (i + 1) %mod;
	}
}

原文地址:https://www.cnblogs.com/waryan/p/12668640.html