组合数学递推及求除法逆元

C(n,m)递推式

c(n,m)=c(n-1,m-1)+c(n-1,m)

证明步骤:使用组合数公式进行拆解并通分,即可得到。这个公式有条件,就是n,m>0且n>m

代码

#include
using namespace std;
#define MOD 1000000007
long long arr[1001][1001];

int main(){

    for(int i = 0;i<=1000;i++){
        for(int j = 0;j<=i;j++){
            if(j==0||i==j)arr[i][j] = 1;
            else{
                arr[i][j] = (arr[i-1][j-1] + arr[i-1][j])%MOD;  
            } 
        }
    }
    printf("%lld\n",arr[500][222]);
    return 0;
}

但是有不足的是,对于n较大m较大时,时间复杂度不允许,是n^2级别,因此此时可以用逆元方式求解

费马小定理

(Fermat’s little theorem)是数论中的一个重要定理,在1636年提出,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p),即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

逆元

若gcd(a,p)=1那么存在唯一x,使得ax=1(mod p)

如:
组合数学递推及求除法逆元_第1张图片

代码有空贴下。

扩展欧几里德

这里介绍一下欧几里得定理来求逆元:

欧几里得是数论中十分重要的一个,我们主要用到其辗转相除求最大公约数。在这里我省略欧几里德算法。讲扩展的欧几里德。

首先知道ax+by=c这个算式,即确定a和b,如果a % b = c那么在这个方程里肯定是有解的,于是我们对其进行扩展。即,根据ax = 1(mod b)这个算法,我们结合其算式,能求出x,即a的逆。
于是我们就能得到这样的算式:
ax1 + by1 = gcd(a,b)
bx2 + (a%b)y2 = gcd(b,a%b)
我们根据欧几里德算法可知gcd(a,b)和gcd(b,a%b)是一样的
ax1 + by1 = gcd(a,b)
bx2 + (a%b)y2 = gcd(a,b)
现在问题如何求解 x2,y2
我们直接得出ax1+by1 = bx2 + (a%b)y2
ax1+by1 = bx2 + (a-a/b*b)y2
ax1+by1 = ay2 + b(x2 -a/b)
x1 = y2
y1 = (x2 -y2a/b)
我们可以清楚的看到,由后面可以推出前面的式子,当然gcd最后会b=0此时ax+by=1时,令x=1,b=任意数,然后进行逆推,推到初始的a和b的方程,x和y就是最简单的解。当然求逆元时,x有时候会为负数,这时需要(x+mod)%mod进行正数取模,保证x为正整数解。

一下为代码,参考其他人的,写的非常简洁,而且能判断时候互质

typedef  long long ll;  
void extgcd(ll a,ll b,ll& d,ll& x,ll& y){  
    if(!b){ d=a; x=1; y=0;}  
    else{ extgcd(b,a%b,d,y,x); y-=x*(a/b); }  
}  
ll inverse(ll a,ll n){  
    ll d,x,y;  
    extgcd(a,n,d,x,y);  
    return d==1?(x+n)%n:-1;  
}

你可能感兴趣的:(数论)