OI模板 卢卡斯定理

博客介绍了 Lucas 定理及其在数论问题中的应用,包括如何利用 Lucas 定理求解 (mn)modp 的模运算,并通过例题 Luogu P2480 进行了说明。此外,还讨论了扩展 Lucas 定理,即当 p 不是质数时的解决方案,包括质因数分解、求解 ai 和 pkn! 的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

卢卡斯定理 / Lucas\text{Lucas}Lucas定理

现有问题:

给定整数 n,m,pn,m,pn,m,p,求 (nm) mod p\dbinom{n}{m}\bmod p(mn)modp,保证 p∈Pp\in\mathbb{P}pP

1≤n,m,p≤1051\leq n,m,p \leq 10^51n,m,p105

可以用 Lucas 定理解决。

定义

对于 p∈Pp\in\mathbb{P}pP,有 (nm) mod p=(⌊n/p⌋⌊m/p⌋)×(n mod pm mod p) mod p\dbinom{n}{m}\bmod p = \dbinom{\lfloor n / p \rfloor}{\lfloor m / p \rfloor}\times\dbinom{n\bmod p}{m\bmod p}\bmod p(mn)modp=(m/pn/p)×(mmodpnmodp)modp

另一种形式:(nm) mod p=∏i=1k(aibi) mod p\dbinom{n}{m}\bmod p = \displaystyle\prod\limits_{i=1}^k\dbinom{a_i}{b_i}\bmod p(mn)modp=i=1k(biai)modpa,ba,ba,b 分别为 n,mn,mn,mppp 进制下的某一位,kkk 是它们 ppp 进制位数的较大值)。

证明

以下的 p∈Pp\in\mathbb{P}pP

∵(pn) mod p=p!n!(p−n)!=[n=0∨n=p]\because\dbinom{p}{n}\bmod p = \displaystyle\frac{p!}{n!(p-n)!}=[n=0 \lor n=p](np)modp=n!(pn)!p!=[n=0n=p]

∴(a+b)p=∑n=0p(pn)anbp−n≡∑n=0p[n=0∨n=p]anbp−n≡ap+bp( mod p)\begin{aligned}\therefore(a+b)^p&=\displaystyle\sum\limits_{n=0}^p\dbinom{p}{n}a^nb^{p-n}\\&\equiv\sum_{n=0}^p[n=0\lor n=p]a^nb^{p-n}\\&\equiv a^p+b^p(\bmod p)\end{aligned}(a+b)p=n=0p(np)anbpnn=0p[n=0n=p]anbpnap+bp(modp)

上面的结论可以用费马小定理推,但是这里没有用。所以这个推导也适用于多项式。

fp(x)=(axn+bxm) mod pf^p(x)=(ax^n+bx^m)\bmod pfp(x)=(axn+bxm)modp,则

(axn+bxm)p≡apxpn+bpxpm≡axpn+bxpm≡f(xp)( mod p)\begin{aligned}(ax^n+bx^m)^p&\equiv a^px^{pn}+b^px^{pm}\\&\equiv ax^{pn}+bx^{pm}\\&\equiv f(x^p)(\bmod p)\end{aligned}(axn+bxm)papxpn+bpxpmaxpn+bxpmf(xp)(modp)

s=⌊np⌋,t=⌊mp⌋,q=n mod p,w=m mod ps=\lfloor\displaystyle\frac{n}{p}\rfloor, t=\lfloor\displaystyle\frac{m}{p}\rfloor,q=n\bmod p, w=m\bmod ps=pn,t=pm,q=nmodp,w=mmodp,则有 n=sp+q,m=tp+wn=sp+q,m=tp+wn=sp+q,m=tp+w

(1+x)n≡((1+x)p)s(1+x)q≡(1+xp)s+(1+x)q≡∑i=1s(si)xpi×∑i=1q(qj)xj( mod p)\begin{aligned}(1+x)^n&\equiv ((1+x)^p)^s(1+x)^q\\&\equiv (1+x^p)^s+(1+x)^q\\&\equiv\sum\limits_{i=1}^s\dbinom{s}{i}x^{pi}\times\sum\limits_{i=1}^q\dbinom{q}{j}x^{j} (\bmod p)\end{aligned}(1+x)n((1+x)p)s(1+x)q(1+xp)s+(1+x)qi=1s(is)xpi×i=1q(jq)xj(modp)

(1+x)n=∑i=1sp+q(sp+qi)xi(1+x)^n=\displaystyle\sum\limits_{i=1}^{sp+q}\dbinom{sp+q}{i}x^i(1+x)n=i=1sp+q(isp+q)xi

∴∑i=1sp+q(sp+qi)xi≡∑i=1s(si)xpi×∑i=1q(qj)xj( mod p)\therefore\displaystyle\sum\limits_{i=1}^{sp+q}\dbinom{sp+q}{i}x^i\equiv\sum\limits_{i=1}^s\dbinom{s}{i}x^{pi}\times\sum\limits_{i=1}^q\dbinom{q}{j}x^{j} (\bmod p)i=1sp+q(isp+q)xii=1s(is)xpi×i=1q(jq)xj(modp)

可以发现,当 m≤nm\leq nmn 时,两边都有 xtp+mx^{tp+m}xtp+m 项。对比两边系数:

(sp+qtp+w)xtp+w≡(st)xtp×(qw)xw(sp+qtp+w)≡(st)×(qw)(nm)≡(⌊np⌋⌊mp⌋)(n mod pm mod p)( mod p) \begin{aligned} \dbinom{sp+q}{tp+w}x^{tp+w}&\equiv \dbinom{s}{t}x^{tp}\times\dbinom{q}{w}x^w\\ \dbinom{sp+q}{tp+w}&\equiv\dbinom{s}{t}\times\dbinom{q}{w}\\ \dbinom{n}{m}&\equiv\dbinom{\lfloor\frac{n}{p}\rfloor}{\lfloor\frac{m}{p}\rfloor}\dbinom{n\bmod p}{m \bmod p}(\bmod p) \end{aligned} (tp+wsp+q)xtp+w(tp+wsp+q)(mn)(ts)xtp×(wq)xw(ts)×(wq)(pmpn)(mmodpnmodp)(modp)

得证。

const int N = 1e5 + 10;
long long A[N];//预处理出阶乘
long long qp(long long a, long long b, long long p);//快速幂
long long C(long long n, long long m, long long p){
    if(m > n) return 0;
    return (A[n] * qp(A[m], p-2, p) % p) * 
           qp(A[n-m], p-2, p) % p;
}
long long Lucas(long long n, long long m, long long p){
    if(!m) return 1;
    return C(n%p, m%p, p) * Lucas(n/p, m/p, p) % p;
}
long long solve(long long n, long long m, long long p){
    A[0] = 1;
    for(int i = 1; i <= n; ++ i) A[i] = A[i-1] * i % p;
    return Lucas(n, m, p);
} 

例题

Luogu P2480 [SDOI2010] 古代猪文(基础数论全家桶)

g∑d∣nCnd mod 999911659g^{\sum_{d|n} C_n^d}\bmod 999911659gdnCndmod999911659

1≤n,g≤1091\leq n,g \leq 10^91n,g109

  • 因为 999911659∈P999911659\in \mathbb{P}999911659P
  • 所以由欧拉定理可知,g999911658≡1( mod 999911659)g^{999911658}\equiv 1(\bmod 999911659)g9999116581(mod999911659),注意这里要有个特判:当 g=999911659g=999911659g=999911659 时直接输出 000 结束程序。
  • 所以原式 =g∑d∣nCnd mod 999911658 mod 999911659=g^{\sum_{d|n} C_n^d\bmod999911658}\bmod 999911659=gdnCndmod999911658mod999911659
  • 999911658=2∗3∗4679∗35617999911658=2*3*4679*35617999911658=23467935617
  • t=∑d∣nCnd mod 999911658t=\sum_{d|n} C_n^d\bmod999911658t=dnCndmod999911658
  • {t≡∑d∣nCnd( mod 2)t≡∑d∣nCnd( mod 3)t≡∑d∣nCnd( mod 4679)t≡∑d∣nCnd( mod 35617)\begin{cases}t\equiv\sum_{d|n} C_n^d(\bmod2)\\t\equiv\sum_{d|n} C_n^d(\bmod3)\\t\equiv\sum_{d|n} C_n^d(\bmod4679)\\t\equiv\sum_{d|n} C_n^d(\bmod35617)\end{cases}tdnCnd(mod2)tdnCnd(mod3)tdnCnd(mod4679)tdnCnd(mod35617)
  • 每一项用 Lucas,然后用 CRT 求 ttt
typedef long long ll;
const int N = 35620, P = 999911658;
ll A[N], x[4], y[4] = {2, 3, 4679, 35617};
ll qp(ll a, ll b, ll p);
ll C(ll n, ll m, ll p);
ll Lucas(ll n, ll m, ll p);
ll CRT(){
    ll ans = 0;
    for(int k = 0; k <= 3; ++ k)
        ans = (ans + x[k] * (P/y[k]) % P * qp(P/y[k], y[k]-2, y[k])) % P;
    return ans;
}
ll solve(ll n, ll g){
    if(g == P + 1) return 0;
    for(int k = 0; k <= 3; ++ k){
        A[0] = 1;
        for(ll i = 1; i <= y[k]; ++ i) A[i] = A[i-1] * i % y[k];
        for(ll i = 1; i * i <= n; ++ i) if(n%i == 0){
            x[k] = (x[k] + Lucas(n, i, y[k])) % y[k];
            if(i * i != n) x[k] = (x[k] + Lucas(n, n/i, y[k])) % y[k];
        }
    }
    return qp(g, CRT(), P+1);
}

扩展卢卡斯定理 / exLucas\text{exLucas}exLucas

问题如下:

给定整数 n,m,pn,m,pn,m,p,求 (nm) mod p\dbinom{n}{m}\bmod p(mn)modp保证 p∈Pp\in\mathbb{P}pP

1≤n,m≤1018,2≤p≤1061\leq n,m \leq 10^{18}, 2\leq p \leq 10^61n,m1018,2p106

其实和 Lucas 没什么关系。以下是解决步骤:

解法

Step 1. 分解 ppp

对于 ppp 进行质因数分解:p=∏i=1rpikip=\prod\limits_{i=1}^r p_i^{k_i}p=i=1rpiki。将原式化成若干同余方程:

{(nm)≡a1( mod p1k1)(nm)≡a2( mod p2k2)...(nm)≡ai( mod piki)\begin{cases}\dbinom{n}{m}\equiv a_1(\bmod p_1^{k_1})\\\dbinom{n}{m}\equiv a_2(\bmod p_2^{k_2})\\...\\\dbinom{n}{m}\equiv a_i(\bmod p_i^{k_i})\end{cases}(mn)a1(modp1k1)(mn)a2(modp2k2)...(mn)ai(modpiki)

因为 pikip_i^{k_i}piki 两两互素,最后使用 CRT 求解即可。

Step 2. 求解 aia_iai

ai=(nm) mod piki=n!m!(n−m)! mod pikia_i=\dbinom{n}{m}\bmod p_i^{k_i}=\displaystyle\frac{n!}{m!(n-m)!}\bmod p_i^{k_i}ai=(mn)modpiki=m!(nm)!n!modpiki,但是 pikip_i^{k_i}piki 仍然不是质数,不能求出分母的逆元。所以将分子分母的所有 pip_ipi 提出来:

ai=n!pik1m!pik2×(n−m)!pik3×pik1−k2−k3a_i=\displaystyle\frac{\frac{n!}{p_i^{k_1}}}{\frac{m!}{p_i^{k_2}}\times\frac{(n-m)!}{p_i^{k_3}}}\times p_i^{k1-k2-k3}ai=pik2m!×pik3(nm)!pik1n!×pik1k2k3,分母可以求逆元。

Step 3.求解 n!pk\displaystyle\frac{n!}{p^k}pkn!

举个例子:n=22,p=3,k=2n=22,p=3,k=2n=22,p=3,k=2

n!=1∗2∗...∗22=37∗(1∗2∗3∗4∗5∗6∗7)∗(1∗2∗4∗5∗7∗8)∗(10∗11∗13∗14∗16∗17)∗(19∗20∗22)≡37∗7!∗(1∗2∗4∗5∗7∗8)2∗(1∗2∗4)( mod pk)\begin{aligned}n!&=1*2*...*22\\&=3^7*(1*2*3*4*5*6*7)*(1*2*4*5*7*8)*(10*11*13*14*16*17)*(19*20*22)\\&\equiv3^7*7!*(1*2*4*5*7*8)^2*(1*2*4)(\bmod p^k)\end{aligned}n!=12...22=37(1234567)(124578)(101113141617)(192022)377!(124578)2(124)(modpk)

分为三个部分

  • 373^737pnpp^{\frac{n}{p}}ppn(会被分母消掉,不用算)。
  • 7!7!7! 递归求解
  • mod  pk\mod p^kmodpk 意义下是循环节,有 npk\frac{n}{p^k}pkn 个,剩下的那部分暴力求解。
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 = qp(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;//递归求解
}

完整代码

typedef long long ll;
const int N = 1e6 + 10;
ll a[N], b[N]; int tot;
ll qp(ll a, ll b, ll p);
void exgcd(ll &x, ll &y, ll a, ll b);
ll inv(ll x, ll p);
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 = qp(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;
}
ll C(ll n, ll m, ll p, ll pk){
    if(!n || !m || n==m) return 1; if(n < m) return 0;
    ll nn = calc(n, p, pk), mm = calc(m, p, pk), nm = calc(n-m, p, pk);
    ll cnt = 0, k = n - m;//cnt即上文k1-k2-k3
    while(n) n /= p, cnt += n;
    while(m) m /= p, cnt -= m;
    while(k) k /= p, cnt -= k;
    return nn * inv(mm, pk) % pk * inv(nm, pk) % pk *
           qp(p, cnt, pk) % pk;
}
ll CRT(){
    ll M = 1, ans = 0;
    for(int i = 1; i <= tot; ++ i) M *= b[i];
    for(int i = 1; i <= tot; ++ i)
        ans += a[i] * (M/b[i]) * inv(M/b[i], b[i]);
    return (ans % M + M) % M;
}
ll exLucas(ll n, ll m, ll p){
    for(ll i = 2; i * i <= p && p >= 1; ++ i){
        ll pk = 1;
        while(p%i == 0) p /= i, pk *= i;
        if(pk > 1) a[++tot] = C(n, m, i, pk), b[tot] = pk;
    }
    if(p > 1) a[++tot] = C(n, m, p, p), b[tot] = p;
    return CRT();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值