Lucas 定理

Lucas 定理

CmnCmmodpnmodpCmpnp(modp)

证明

规定:invx 表示 x 在模 p 意义下的逆元

定理 1

Cpxp×invx×Cp1x10(modp)(0<x<p)

证明:

Cpx=p!x!(px)!=p(p1)!x(x1)!(px)!=px(p1)!(x1)![(p1)(x1)]!=pxCp1x1pinvxCp1x1(modp)

定理 2

(1+x)p1+xp(modp)

根据二项式定理

(1+x)p=i=0pCpixi1pi=i=0pCpixiCpxpinvxCp1x10(modp)(0<x<p)(1+x)p=Cp0x0+Cppxp=1+xp

推 式 子

{s=mpr=mmodp,则 m=sp+r

(1+x)m=k=0mCmkxk(1+x)m=(1+x)sp+r=(1+x)sp(1+x)r=[(1+x)p]s(1+x)r(1+xp)s(1+x)r(modp)=i=0sCsixipj=0rCrjxj=i=0sj=0rCsiCrjxip+j

因为 ip+j 刚好会枚举到 [0,m] 中的整数各一次(对于每个在 [0,m] 中的整数 x 都可以拆成 xpp+xmodp 的形式,而 i=xp,j=xmodp),所以转而枚举 k=ip+j

(1+x)mk=0mCskpCrkmodp(modp)

k=n,则

CmnCsnpCrnmodp=CmmodpnmodpCmpnp(modp)

得证.

代码实现

例题:洛谷 P3807 【模板】卢卡斯定理

如果寻求高效率,建议先预处理出 0~p 在模 p 意义下的逆元和 0~p 的阶乘:

for(int i=2;i<=p;i++)
{
      fac[i]=1ll*fac[i-1]*i%p;
      inv[i]=1ll*(p-p/i)*inv[p%i]%p;
}

然后再处理出 0~p 的阶乘的逆元:

for(int i=2;i<=p;i++)
      inv[i]=1ll*inv[i-1]*inv[i]%p;
//注意不能和求0~p的逆元放一起做!!!

然后就是快快乐乐的 Lucas 了:

int C(int _m,int _n,int mod)
{
	if(_n>_m) return 0;
	return 1ll*fac[_m]*inv[_n]%mod*inv[_m-_n]%mod;
}
int Lucas(int _m,int _n,int mod)
{
	if(_n==0){return 1;}
	else return 1ll*C(_m%mod,_n%mod,mod)*Lucas(_m/mod,_n/mod,mod)%mod;
}
posted @   Mine_King  阅读(169)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示