exLucas 算法学习笔记
一、问题
给定
二、解法
首先,数论题一个常见的做法:如果模数不一定是质数,那就把模数拆成若干个质数的积,然后分别求解,最后用中国剩余定理求解。
1. 拆
我们可以把
然后对于每一个
2. 求
这等同于求
但是我们不一定能求出
所以我们要手动让它们互质。
原式可以表示为
然后我们可以用
3. 求
这可以用到 Legendre 公式,也就是
所以直接按照这个求即可,时间复杂度
4. 求
由于这个数可能很大,我们求的其实是
好像就是
考虑用另一种方法计算。我们注意到
由于
所以
递归调用
5. 总时间复杂度
假设
- 质因数分解,时间复杂度是
。 - 对于
预处理 ,总时间复杂度是 。 - 求
,因为至多调用计算函数 次,所以这个部分的上界是 。 - 用中国剩余定理合并,一共合并
次,一次时间复杂度 ,总时间复杂度 。
所以总时间复杂度是
三、代码
变量名与上文不完全对应。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,m,p,c=0,s[1000010],a[1010],b[1010];
inline void exgcd(ll &x,ll &y,ll a,ll b){
if(!b){x=1;y=0;return;}
exgcd(y,x,b,a%b);y-=a/b*x;
}
inline ll ksm(ll a,ll b,ll p){
ll r=1;
while(b){if(b&1)r=r*a%p;a=a*a%p;b>>=1;}
return r;
}
inline ll inv(ll n,ll p){
ll x,y;
exgcd(x,y,n,p);
return (x%p+p)%p;
}
inline ll G(ll n,ll p){
ll r=0;
while(n)n/=p,r+=n;
return r;
}
inline ll F(ll n,ll p,ll pk){
if(!n)return 1;
return F(n/p,p,pk)*ksm(s[pk-1],n/pk,pk)%pk*s[n%pk]%pk;
}
inline ll qwq(ll n,ll m,ll p,ll pk){
s[0]=1;
for(ll i=1;i<pk;i++)
if(i%p)s[i]=s[i-1]*i%pk;
else s[i]=s[i-1];
ll nowf=F(n,p,pk)*inv(F(m,p,pk)*F(n-m,p,pk)%pk,pk)%pk;
ll nowg=ksm(p,G(n,p)-G(m,p)-G(n-m,p),pk);
return nowf*nowg%pk;
}
inline ll exlucas(ll x,ll y,ll p){
ll r=0,P=p;
for(ll i=2;i*i<=p;i++)
if(p%i==0){
a[++c]=1;
while(p%i==0)p/=i,a[c]*=i;
b[c]=qwq(x,y,i,a[c]);
}
if(p>1)a[++c]=p,b[c]=qwq(x,y,p,p);
for(ll i=1,x,y;i<=c;i++)r=(r+inv(P/a[i],a[i])*P/a[i]%P*b[i]%P)%P;
return r;
}
int main(){
cin>>n>>m>>p;
cout<<exlucas(n,m,p)<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!