Lucas & exLucas

Lucas&exLucas:

Lucas

(nm)(npmp)(nmodpmmodp)(modp)

这里 p 是质数(nm)=Cnm
证明(jijidawang闲话)

exLucas

对于 p 不是质数的情况:

总:

  1. p 进行质因数分解,令:

    p=inpiki(pi)

    将原式变为求 x ,满足:

    xCnm(modpiki)(1in)

  2. 求解每个 1in 对应的 Cnmmodpiki 的值。
  3. crt 合并即可(显然 piki 两两互质)。

1. 质因数分解:

挺简单,略。

2. 求Cnmmodpiki(重难点)

首先将 C 展开:

n!m!(nm!)modpiki

因为分母与模数不一定互质,于是考虑提取因数:

n!pia1m!pia2×(nm)!pia3×pia1a2a3modpiki

然后就可以乘法逆元( inv(a) 表示 amodpiki 意义下的逆元):

n!pia1×inv(m!pia2)×inv((nm)!pia3)×pia1a2a3modpiki

接下来有两个问题:求 n!piayay

先求 n!piay ,设 P=piay
n! 变形

n!=1×2×...×n=(P×2P×...×nPP)×(1×2×...)

左边为可以整除 piay ,右边为不能的。
在化简一下:

(1)n!=PnP×(nP)!×i=1,i0(modP)n

第一段 ÷p 没了,第二段可以递归。
看第三段,发现它在 modpiki 显然有循环节,于是我们将它变形为:

(i=1,i0(modP)piki)npiki×i=1,i0(modP)nmodpiki 

然后暴力+快速幂算即可。

然后考虑求 ay ,我们用 G(x) 表示 n!pia 中的 a
我们发现,ay 就是 (1) 中的 nP ,将其带入 (1) 中递归里,可以得出

G(n)=G(nP)+nP

边界:G(0)=0 ,于是可以递归求解。

crt合并:

可以参照 this

例题

CODE(点击查看)
//分清pi、pk。
#include<bits/stdc++.h>
using namespace std;
#define llt long long
llt MOD,n,m;
template<typename T>
inline void read(T &x){
char s=getchar();x=0;bool pd=false;
while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();}
while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
if(pd) x=-x;
}
inline llt fpw(llt a,llt b,llt Mod){
llt pan=1;
while(b){
if(b&1) pan=pan*a%Mod;
a=a*a%Mod,b>>=1;
}
return pan;
}
inline void exgcd(llt a,llt b,llt &x,llt &y){
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
inline llt inv(llt a,llt Mod){
llt x,y;exgcd(a,Mod,x,y);
return (x%Mod+Mod)%Mod;
}
inline llt fac(llt a,llt pi,llt pk){
if(!a) return 1;
llt cnt=1;
for(int i=2;i<=pk;i++) if(i%pi) cnt=cnt*i%pk;
cnt=fpw(cnt,a/pk,pk);
for(int i=2;i<=a%pk;i++) if(i%pi) cnt=cnt*i%pk;
return cnt*fac(a/pi,pi,pk)%pk;
}
llt up(llt x,llt p){return (x)?x/p+up(x/p,p):0;}
inline llt get_c(llt pi,llt pk,llt x,llt y){
llt fx=fac(x,pi,pk),fy=fac(y,pi,pk),fxy=fac(x-y,pi,pk);
return fx*inv(fy,pk)%pk*inv(fxy,pk)%pk*fpw(pi,up(n,pi)-up(m,pi)-up(n-m,pi),pk)%pk;
}
inline llt crt(llt a,llt Mod){
return a*(MOD/Mod)%MOD*inv(MOD/Mod,Mod)%MOD;
}
inline llt exlucas(llt x,llt y){
llt p=MOD,ans=0;
for(int i=2;i*i<=p;i++){
if(p%i) continue;
llt pk=1;
while(p%i==0) p/=i,pk*=i;
ans=(ans+crt(get_c(i,pk,x,y),pk))%MOD;
}
if(p>1) ans=(ans+crt(get_c(p,p,x,y),p))%MOD;
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
read(n),read(m),read(MOD);
printf("%lld",exlucas(n,m));
}
posted @   5k_sync_closer  阅读(17)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示