首页 > 代码库 > 【学习总结】数学-lucas定理

【学习总结】数学-lucas定理

定义:

数论Lucas定理是用来求 C(mn)%p的值,p是素数.

描述:

lucas(n,m,p)=lucas(n/p,m/p,p)?C(m%pn%p)
lucas(n,0,p)=1

证明:

p为素数,A,B为正整数,并且有(即ABp进制情况):
A=akpk+ak?1pk?1++a1p1+a0
B=bkpk+bk?1pk?1++b1p1+b0

因为C(jp)=C(j?1p?1)?pj=0 (含有因子p)
所以(1+x)t(modp)=(1+xt)(modp) (中间展开项均含有C(ip))

于是乎,我们让t=A
(1+x)A=(1+x)akpk+ak?1pk?1++a1p1+a0(modp)
=(1+x)akpk?(1+x)ak?1pk?1??(1+x)a0(modp)
=(1+xpk)ak?(1+xpk?1)ak?1??(1+x)a0(modp)
对比两边xb的系数,根据多项式定理和p进制数的性质(A对应的p进制,导致了系数的确定)
C(BA)=C(bkak)?C(bk?1ak?1)??C(b0a0)

代码:

typedef long long ll;

ll n, m, p;

ll qPow (ll a, ll k) {
    ll ans = 1;

    while (k) {
        if (k&1)
            ans = (ans * a) % p;
        a = (a * a) % p;
        k /= 2;
    }
    return ans;
}

ll C (ll a, ll b, ll p) {

    if (a < b)
        return 0;

    if (b > a - b)
        b = a - b;

    ll up = 1, down = 1;

    for (ll i = 0; i < b; i++) {
        up = up * (a-i) % p;
        down = down * (i+1) % p;
    }
    return up * qPow(down, p-2) % p; // 逆元
}

ll lucas (ll a, ll b, ll p) {
    if (b == 0)
        return 1;
    return C(a%p, b%p, p) * lucas(a/p, b/p, p) % p;
}