简单数论(一)

快速幂

用途

求a^p

代码

inline int Pow(int a,int b)
{
    int ans = 1;
    int mul = a;
    while(b)
    {
        if(b&1) ans *= mul;
        mul*=mul;
        b>>=1;
    }
    return ans;
}

 

时间复杂度

O(log p)

欧几里德算法

用途

欧几里德算法又称辗转相除法,是指用于计算两个正整数a,b的最大公约数

代码

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

 

时间复杂度

时间复杂度:显然经过两次递归后第一个参数至少减小一半 所以时间复杂度粗略为O(log max(a,b))

扩展欧几里得算法

用途

扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d

代码

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

 

 

时间复杂度

时间复杂度粗略为O(log max(a,b))

乘法逆元

用途

除以一个数取模等于乘以这个数的逆元取模

    假设b存在乘法逆元,即与m互质(充要条件)。
    设c是b的逆元,即b∗c≡1(mod m),那么有a/b=(a/b)∗1=
    (a/b)∗b∗c=a∗c(mod m) 

求解方法

    逆元求解一般利用扩欧。
    当m为质数的时候直接使用费马小定理,m非质数使用欧拉函数。
    当m为质数的时候,有线性方法。(一般求1-N的逆元时用)
扩展欧几里得算法

说明略。。。

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

 

此时逆元为(x+mod)%mod(有可能有负数) 若 d 用来判断有没有逆元

费马小定理

若p是质数,则

 a^(p-1)%m==1

所以逆元为a^p-2,用快速幂即可

代码

时间复杂度

O(log p)
费马小定理额外作用

a^m = a^(m%(p-1))

O(n)时间求1~n逆元
 inv[1]=1;
    for(register int i=2;i<=n;i++)
        inv[i]=(long long)(p-p/i)*inv[p%i]%p;

 

证明
证明:
设t = MOD / i , k = MOD % i
则有 t * i + k == 0 % MOD
有 -t * i == k % MOD
两边同时除以ik得到
-t * inv[k] == inv[i] % MOD
即
inv[i] == -MOD / i * inv[MOD%i]
即
inv[i] == ( MOD - MOD / i) * inv[MOD%i]

逆元的更多应用

快速求阶乘的逆元:

首先要求出 1! 2!。。。n! 的值, 先求出 n!的逆元。 逆元是积性函数, 可以根据n!的逆元 求出 1! 2!。。。(n-1)!的逆元。

(n!)^(-1)= (n-1)!^(-1)  *  n^(-1)   移项得

( (n!)^(-1) )/( n^(-1) ) = (n-1)! ^ (-1)   根据除以一个数等价于乘以这个数的逆元

(n!)^(-1) * n = (n-1)! ^ (-1)

有什么用

求组合数C(n,m)%p的结果

C(n,m)=n!/(n-m)!*m!

只需求出(n-m)!*m!的逆元p1

再计算n!%p*p1%p即可

posted @ 2018-04-15 12:36  wlzs1432  阅读(376)  评论(0编辑  收藏  举报