Lucas & exLucas

\(Lucas\&exLucas\):

\(Lucas\)

\[\dbinom nm\equiv\dbinom{\lfloor\frac np\rfloor}{\lfloor\frac mp\rfloor}\dbinom{n\bmod p}{m\bmod p}\pmod p \]

这里 \(p\) 是质数\(\tbinom nm = C_n^m\)
证明(jijidawang闲话)

\(exLucas\)

对于 \(p\) 不是质数的情况:

总:

  1. \(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) \]

  2. 求解每个 \(1\le i\le n\) 对应的 \(C_n^m\bmod p_i^{k_i}\) 的值。
  3. \(crt\) 合并即可(显然 \(p_i^{k_i}\) 两两互质)。

1. 质因数分解:

挺简单,略。

2. 求\(C_n^m\bmod p_i^{k_i}\)(重难点)

首先将 \(C\) 展开:

\[\frac{n!}{m!(n-m!)} \bmod p_i^{k_i} \]

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

\[\dfrac{\dfrac{n!}{p_i^{a_1}}}{\dfrac{m!}{p_i^{a_2}}\times\dfrac{(n-m)!}{p_i^{a_3}}}\times p_i^{a_1-a_2-a_3}\bmod p_i^{k_i} \]

然后就可以乘法逆元( \(inv(a)\) 表示 \(a\)\(\bmod p_i^{k_i}\) 意义下的逆元):

\[\frac{n!}{p_i^{a_1}}\times inv\left(\frac{m!}{p_i^{a_2}}\right)\times inv\left(\frac{(n-m)!}{p_i^{a_3}}\right)\times p_i^{a_1-a_2-a_3}\bmod p_i^{k_i} \]

接下来有两个问题:求 \(\frac{n!}{p_i^{a_y}}\)\(a_y\)

先求 \(\frac{n!}{p_i^{a_y}}\) ,设 \(P= p_i^{a_y}\)
\(n!\) 变形

\[n!=1\times 2\times ... \times n=(P\times 2P\times...\times \left\lfloor\frac{n}{P} \right\rfloor P)\times(1\times2\times...) \]

左边为可以整除 \(p_i^{a_y}\) ,右边为不能的。
在化简一下:

\[n!=P^{\left\lfloor\frac{n}{P} \right\rfloor}\times\left(\left\lfloor\frac{n}{P} \right\rfloor\right)!\times \prod\limits_{i=1,i\not\equiv0\pmod P}^n\tag1 \]

第一段 \(\div p\) 没了,第二段可以递归。
看第三段,发现它在 \(\bmod p_i^{k_i}\) 显然有循环节,于是我们将它变形为:

\[\left(\prod\limits_{i=1,i\not\equiv0\pmod P}^{p_i^{k_i}}\right)^{\left\lfloor\frac{n}{p_i^{k_i}} \right\rfloor}\times\prod\limits_{i=1,i\not\equiv0\pmod P}^{n\bmod p_i^{k_i}}\ \]

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

然后考虑求 \(a_y\) ,我们用 \(G(x)\) 表示 \(\frac{n!}{p_i^{a}}\) 中的 \(a\)
我们发现,\(a_y\) 就是 (1) 中的 \(\left\lfloor\frac{n}{P} \right\rfloor\) ,将其带入 (1) 中递归里,可以得出

\[G(n)=G\left(\left\lfloor\frac{n}{P} \right\rfloor\right)+\left\lfloor\frac{n}{P} \right\rfloor \]

边界:\(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 @ 2023-02-03 14:50  xrlong  阅读(13)  评论(0编辑  收藏  举报