ACM_数论

1.扩展欧几里得

求解线性方程 ax≡b(mod m)
对于实数运算下的方程 ax=b 是不是很好解决啊
如果在mod m的运算下,也有ay≡1(mod m) 这样的a的倒数存在,方程就可以求解了
我们把这样的y叫做a的逆元 记为a^-1
为什么要有乘法逆元呢?
当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。
我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,即(a*k) mod p。其结果与(a/b) mod p等价。

根据b*k≡1 (mod p)有b*k=p*x+1。
k=(p*x+1)/b。 这里的k就是b的乘法逆元
把k代入(a*k) mod p,得:
(a*(p*x+1)/b) mod p
=((a*p*x)/b+a/b) mod p
=[((a*p*x)/b) mod p +(a/b)] mod p
=[(p*(a*x)/b) mod p +(a/b)] mod p
//p*[(a*x)/b] mod p=0
所以原式等于:(a/b) mod p


请别把b^(-1)看成倒数,这会在后面引起思维的混乱,他是逆元!!
记住b^(-1)*b%p =1
更简单的证明: a/b mod p = a* (b*b^(-1) ) /b =a*b^(-1);


讲了挺多废话,你还是没告诉我怎么求逆元啊

ax≡1 (mod p)
ax=mp+1 //对吧?
ax-mp=1 //对吧?
a知道,p知道,x我要求的,m我不知道,怎么做啊?
下面的ll代表long long类型

ll extGCD(ll a,ll b, ll &x,ll &y){   //计算ax+by=gcd(a,b) 中x,y的值
    if(!b){  //b=0加个特判 ax=gcd(a,b)=a -> x=1  
        x=1;
        y=0;
        return a;
    }
    ll gcd=extGCD(b,a%b,x,y);
    ll t=x;
    x=y;
    y=t-a/b*y;
    return gcd;
}

代码看完了,一万个草泥马,你这写的啥玩意啊,第一步我懂,后面讲的什么东西?
梳理一下
gcd(a , b) = gcd(b , a mod b) 没错吧

a*x+b*y = gcd(a , b) //嗯
= gcd(b , a mod b) //没错
= b * x1 + (a mod b) * y1 //他好像倒着用了第一步
= b * x1 + (a - a / b * b) * y1 即 //soga
a*x+b*y = b * x1 + (a - a / b * b) * y1
化简上式,得
a*x+b*y = a*y1 - b*a/b*y1 + b*x1 , 即
a * x + b * y
= a * y1 + b * (x1-a/b*y1)

x=y1
y=x1 - a/b*y1 

上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。回头看看代码,是不是很有趣
以上推论看了别人的思考:知乎

回到求逆元的问题
ax-my=1
如何用扩展欧几里得呢

ll rev(ll a, ll mod){//求a在模mod意义下的乘法逆元 

    ll x,y; //y是多少并不关心,他只是一个倍数
    extGCD(a,mod,x,y);  //a*x+mod*y=1    gcd(a,mod),当mod和a互素=1
    return (x%mod+mod)%mod;
}

2.组合数
除了求解线性方程,逆元的作用何在

    fact[0]=1; //预处理阶乘表
    for(int i=1;i<MAXN;i++){
        fact[i]=(fact[i-1]*i)%MOD;
    }

    ll C(ll n,ll m){    //n个里选m         n!/(m!)*(n-m)!
        if(n<m) return 0;
        return fact[n]*rev(fact[m],MOD)%MOD*rev(fact[n-m],MOD)%MOD;
    }

猜你喜欢

转载自blog.csdn.net/qq_38677814/article/details/80202772