Lucas & exLucas
\(Lucas \And exLucas\):
\(Lucas\)
这里 \(p\) 是质数,\(\tbinom nm = C_n^m\) 。
\(exLucas\)
对于 \(p\) 不是质数的情况:
总:
-
对 \(p\) 进行质因数分解,令:
\[p=\prod\limits_{i}^{n}p_i^{k_i} (p_i 是质数) \]将原式变为求 \(x\) ,满足:
\[x\equiv C_n^m\pmod {p_i^{k_i}} (1 \le i \le n) \] -
求解每个 \(1\le i\le n\) 对应的 \(C_n^m\bmod p_i^{k_i}\) 的值。
-
\(crt\) 合并即可(显然 \(p_i^{k_i}\) 两两互质)。
1. 质因数分解:
挺简单,略。
2. 求\(C_n^m\bmod p_i^{k_i}\)(重难点)
首先将 \(C\) 展开:
因为分母与模数不一定互质,于是考虑提取因数:
然后就可以乘法逆元:
接下来有两个问题:求 \(\frac{n!}{p_i^{a_y}}\) 和 \(a_y\)。
先求 \(\frac{n!}{p_i^{a_y}}\)。
将 \(n!\) 变形
左边为可以整除 \(p_i\) ,右边为不能的。
在化简一下:
第一段 \(\div p_i^{a_y}\) 没了,第二段可以递归。
看第三段,发现它在 \(\bmod p_i^{k_i}\) 显然有循环节,于是我们将它变形为:
然后暴力+快速幂算即可。
然后考虑求 \(a_y\) ,我们用 \(G(x)\) 表示 \(\frac{n!}{p_i^{a}}\) 中的 \(a\)。
我们发现,\(a_y\) 就是 (1) 中的 \(\left\lfloor\frac{n}{p_i} \right\rfloor\) ,将其带入 (1) 中递归里,可以得出
边界:\(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));
}
本文来自博客园,作者:xrlong,转载请注明原文链接:https://www.cnblogs.com/xrlong/articles/17619325.html
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。