Lucas定理
P3807 【模板】Lucas定理
此为费马小定理求解逆元版本
且只讲述如何做这道题 不讲定理证明
一、前置知识
1、费马小定理
当
有
2、乘法逆元
若有
(1)逆元作用
我们在在求解
时,直接算
但我们做除法取模又是要高效且准确无误的算法,所以这里乘法逆元就起了作用。
我们可以设
将两式可以相乘得到
即
由上可知,利用乘法逆元可以避免除法取模中精确度的问题
二、求解逆元
对费马小定理及乘法逆元有理解后,我们可以轻易求解逆元了。
不难看出
求解逆元代码如下:
ll ksm(ll x,ll y,ll mod)//快速幂
{
ll ans=1;
while(y)
{
if(y&1) ans*=x,ans%=mod;
x*=x,y>>=1;
}
return ans;
}
ll mul_inverse(ll b,ll a,ll mod)//求b/a(mod p)
{
return b*ksm(a,mod-2,mod)%mod;//ksm(a,mod-2,mod)是a的乘法逆元
}
三、Lucas定理
这个定理主要用于求大组合数
定理内容:
代码实现方法:递归或循环求解
至于定理证明就问度娘吧(懒得打
四、程序代码
#include<cstdio>
#define ll long long
using namespace std;
int T;
ll n,m,p;
ll ksc(ll x,ll y,ll mod)//快速乘
{
ll ans=0;
while(y)
{
if(y&1) ans+=x,ans%=mod;
x<<=1,x%=mod,y>>=1;
}
return ans;
}
ll ksm(ll x,ll y,ll mod)//快速幂
{
ll ans=1;
while(y)
{
if(y&1) ans=ksc(ans,x,mod),ans%=mod;
x=ksc(x,x,mod),y>>=1;
}
return ans;
}
ll mul_inverse(ll x,ll y,ll mod)//求组合数对mod的取模(要用乘法逆元)
{
if(x<y) return 0;
if(x==y) return 1;//特判,不需要进行计算
if(y>x/2) y=x-y;//方便计算
ll ans,mx=1,my=1;
for(int i=0;i<y;i++)
{
mx*=(x-i),mx%=mod;
my*=(y-i),my%=mod;
}
ans=mx*ksm(my,mod-2,mod)%mod;
return ans;
}
ll lucas(ll x,ll y,ll mod)//lucas定理主体(将x和y转成mod进制)
{
ll ans=1;
while(x&&y)
{
ans*=mul_inverse(x%mod,y%mod,mod),ans%=mod;
x/=mod,y/=mod;
}
return ans;
}
int main()
{
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
scanf("%lld%lld%lld",&n,&m,&p);
printf("%lld\n",lucas(n+m,n,p));
}
return 0;
}
这是我之前在洛谷博客的第一篇文章。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)