ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Lucas定理学习笔记

2022-08-04 21:34:18  阅读:147  来源: 互联网

标签:lfloor ll Lucas bmod 笔记 times rfloor 定理 dbinom


概念

当 \(p\) 是一个质数时,有

\[\dbinom{n}{m} \bmod p \equiv \dbinom{\lfloor \dfrac{n}{p} \rfloor}{\lfloor \dfrac{m}{p} \rfloor} \times \dbinom{n \bmod p}{m \bmod p} \pmod{p} \]

实现

引理:

考虑

\[\dbinom{p}{n} \bmod p \]

的取值,注意到展开之后其为如下形式

\[\dbinom{p}{n} = \dfrac{p!}{n!(p-n)!} \]

显然,分子中一定有质因子 \(p\) ,因此仅当 \(n=0\) 或 \(n=p\) 时,\(n!(p-n)!\) 的质因子中有 \(p\) (即 \(p!\) 能被消干净),结果为 \(1\) ,否则结果为 \(0\) ,即

\[\dbinom{p}{n} \bmod p = [n=0 \lor n=p] \]

进而我们可推出

\[\begin{aligned} (a+b)^p &= \sum_{n=0}^{p}\dbinom{p}{n} a^n b^{p-n} \\ &\equiv \sum_{n=0}^{p} [n=0 \lor n=p]a^nb^{p-n} &\pmod{p} \\ &\equiv a^p + b^p &\pmod{p} \end{aligned} \]

将其推广到二项式,得到

\[\begin{aligned} (ax^n+by^m)^p &\equiv a^px^{np}+b^py^{mp} &\pmod{p} \\ &\equiv ax^{np}+by^{mp} &\pmod{p} \end{aligned} \]

证明:考虑二项式 \((1+x)^n\) 在 \(x^m\) 处的系数模 \(p\) 的结果 \(\dbinom{n}{m} \bmod p\)

利用上述引理,我们可以得到

\[\begin{aligned} (1+x)^n &\equiv (1+x)^{p \lfloor \frac{n}{p} \rfloor} (1+x)^{n \bmod p} &\pmod{p} \\ &\equiv (1+x^p)^{\lfloor \frac{n}{p} \rfloor} (1+x)^{n \bmod p} &\pmod{p} \end{aligned} \]

我们将其看作 \((1+x^p)^{\lfloor \frac{n}{p} \rfloor}\) 与 \((1+x)^{n \bmod p}\) 的卷积,考虑这两个式子对 \((1+x)^n\) 产生的贡献

  • \((1+x^p)^{\lfloor \frac{n}{p} \rfloor}\) 展开后得到的项的次数均为 \(p\) 的倍数
  • \((1+x)^{n \bmod p}\) 展开后得到的项的次数最多为 \(p-1\)

因此,对于 \(x^m\) 的系数仅有一种产生贡献的方案,考虑一下这个贡献怎么来的:就是 \((1+x^p)^{\lfloor \frac{n}{p} \rfloor}\) 中取 \(p\) 的倍数次项,这部分的系数即为 \(\dbinom{\lfloor \dfrac{n}{p} \rfloor}{\lfloor \dfrac{m}{p} \rfloor}\) ,然后再 \((1+x)^{n \bmod p}\) 中取剩余部分,这部分系数即为 \(\dbinom{n \bmod p}{m \bmod p}\)

所以我们可以得出结论(Lucas 定理):

\[\dbinom{n}{m} \bmod p \equiv \dbinom{\lfloor \dfrac{n}{p} \rfloor}{\lfloor \dfrac{m}{p} \rfloor} \times \dbinom{n \bmod p}{m \bmod p} \pmod{p} \]

其中 \(p\) 为质数

P3807 【模板】卢卡斯定理/Lucas 定理

#include <cstdio>
typedef long long ll;
using namespace std;
const int N = 1e5 + 7;

ll fac[N];

ll T, n, m, p;

template<class T>
inline T mi(T _a, T _b, T _Mod) {
    T _res = 1;

    for (; _b; _a = _a * _a % _Mod, _b >>= 1)
        (_b & 1) && (_res = _res * _a % _Mod);

    return _res;
}

inline ll C(ll n, ll m) {
    return (m > n) ? 0 : ((fac[n] * mi(fac[m], p - 2, p)) % p * mi(fac[n - m], p - 2, p) % p);
}

inline ll Lucas(ll n, ll m) {
    return m ? (C(n % p, m % p) * Lucas(n / p, m / p) % p) : 1;
}

signed main() {
    scanf("%lld", &T);

    for (; T; --T) {
        scanf("%lld%lld%lld", &n, &m, &p);
        fac[0] = 1;

        for (int i = 1; i <= p; ++i)
            fac[i] = (fac[i - 1] * i) % p;

        printf("%lld\n", Lucas(n + m, n));
    }

    return 0;
}

扩展

Lucas 定理中对于模数要求必须为质数,那么对于模数不是质数的情况,就需要用到 exLucas 定理,即扩展 Lucas 定理

前置芝士:中国剩余定理

第一部分

根据唯一分解定理,将模数 \(p\) 分解

\[p = \prod_{i=1}^{r} q_i^{k_i} \]

显然,\(q_i^{k_i}\) 两两互质,我们便可以构造如下的同余方程组

\[\begin{cases} x \equiv \dbinom{n}{m} \pmod{q_1^{k_1}} \\ x \equiv \dbinom{n}{m} \pmod{q_2^{k_2}} \\ ... \\ x \equiv \dbinom{n}{m} \pmod{q_r^{k_r}} \end{cases} \]

用中国剩余定理合并即可得出答案

第二部分

现在的问题转化为了求 \(\dbinom{n}{m} \bmod q^k\) 的值(其中 \(q\) 保证为质数)

注意到

\[\dbinom{n}{m} = \dfrac{n!}{m!(n-m)!} \]

但是 \(m!,(n-m)!\) 这两部分不一定能求出模 \(q^k\) 意义下的逆元,我们可以把上下 \(3\) 个部分中的所有含 \(q\) 项的东西提取出来,即

\[\dfrac{\dfrac{n!}{q^x}}{\dfrac{m!}{q^y} \ \dfrac{(n-m)!}{q^z}}q^{x-y-z} \pmod{q^k} \]

此时下面的部分与 \(q^k\) 互质,就可以直接求逆元了

第三部分

我们现在考虑求 \(\dfrac{n!}{q^x} \bmod q^k\) 的值

先考虑 \(n! \bmod p^k\) 的值,例如我们要计算 \(19! \bmod 3^2\)

因为

\[\begin{aligned} 20 &= 1 \times 2 \times 3 \times 4 \times 5 \times 6 \times 7 \times 8 \times 9 \times 10 \times 11 \times 12 \times 13 \times 14 \times 15 \times 16 \times 17 \times 18 \times 19 \times 20 \\ &=3^6 \times 6! \times (1 \times 2 \times 4 \times 5 \times 7 \times 8) \times (10 \times 11 \times 13 \times 14 \times 16 \times 17) \times 20 \end{aligned} \]

我们注意这个式子的前面两项

  • \(3^6\) 即 \(q^{\lfloor \frac{n}{q} \rfloor}\) ,在递归过程中会被约掉
  • \(6!\) 即 \(\lfloor \frac{n}{q} \rfloor!\) ,递归解决即可

对于中间几个括号的部分,注意到

\[1 \times 2 \times 4 \times 5 \times 7 \times 8 \equiv 10 \times 11 \times 13 \times 14 \times 16 \times 17 \pmod{3^2} \]

同理可得后面的每一部分数字的乘积等于前面的数字的乘积,且每个部分相差 \(p^k\) ,用快速幂解决即可

对于最后面残余下的 \(20\) ,我们暴力计算即可

整理一下,我们可以得到

\[\dfrac{n!}{q^x} \equiv \lfloor \dfrac{n}{q} \rfloor ! \times \Bigg(\prod_{i,i \bot q}^{q^k} i \Bigg)^{\lfloor \frac{n}{q^k} \rfloor} \times \Bigg(\prod_{i,i \bot q}^{n \bmod q^k} i \Bigg) \pmod{q^k} \]

第四部分

我们考虑如何求出第二部分中 \(x,y,z\) 的值

令 \(h(n)\) 为 \(n!\) 中 \(q\) 的次数,即 \(h(n)=x\)

考虑当前求 \(n!\) 中 \(q\) 的倍数产生的贡献和下面求 \(\lfloor \dfrac{n}{q} \rfloor\) 中 \(q\) 的倍数产生的贡献

\[h(n) = \lfloor \dfrac{n}{q} \rfloor + h(\lfloor \dfrac{n}{q} \rfloor) \]

P4720 【模板】扩展卢卡斯定理/exLucas

#include <cstdio>
typedef long long ll;
using namespace std;

ll n, m, p;

template<class T>
inline T mi(T _a, T _b, T _Mod) {
    T _res = 1;

    for (; _b; _a = _a * _a % _Mod, _b >>= 1)
        (_b & 1) && (_res = _res * _a % _Mod);

    return _res;
}

template<class T>
inline T exgcd(T a, T b, T &x, T &y, T d = 0) {
    return b ? (d = exgcd(b, a % b, y, x), y -= a / b * x) : (x = 1, y = 0, d = a), d;
}

inline ll inv(ll a, ll b) {
	ll x = 0, y = 0;
    return exgcd(a, b, x, y), (x % b + b) % b;
}

inline ll calc(ll n, ll p, ll pk) {
    if (!n)
        return 1;

    ll ans = 1;

    for (ll i = 1; i <= pk; ++i)
        if (i % p)
            ans = (ans * i) % pk;

    ans = mi(ans, n / pk, pk);

    for (ll i = 1; i <= n % pk; ++i)
        if (i % p)
            ans = (ans * i) % pk;

    return ans * calc(n / p, p, pk) % pk;
}

inline ll C(ll n, ll m, ll p, ll pk) {
    if (n < m)
        return 0;

    ll f1 = calc(n, p, pk), f2 = calc(m, p, pk), f3 = calc(n - m, p, pk), cnt = 0;

    for (ll i = n; i; i /= p)
        cnt += i / p;

    for (ll i = m; i; i /= p)
        cnt -= i / p;

    for (ll i = n - m; i; i /= p)
        cnt -= i / p;

    return f1 * inv(f2, pk) % pk * inv(f3, pk) % pk * mi(p, cnt, pk) % pk;
}

inline ll CRT(ll x, ll p, ll mod) {
    return inv(p / mod, mod) * (p / mod) * x;
}

inline ll exLucas(ll n, ll m, ll p) {
    ll t = p, ans = 0;

    for (ll i = 2, k; i * i <= p; ++i) {
        k = 1;

        while (!(t % i))
            k *= i, t /= i;

        ans = (ans + CRT(C(n, m, i, k), p, k)) % p;
    }

    if (t > 1)
        ans = (ans + CRT(C(n, m, t, t), p, t)) % p;

    return ans;
}

signed main() {
    scanf("%lld%lld%lld", &n, &m, &p);
    printf("%lld", exLucas(n, m, p));
    return 0;
}

标签:lfloor,ll,Lucas,bmod,笔记,times,rfloor,定理,dbinom
来源: https://www.cnblogs.com/wshcl/p/Lucas.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有