Luogu3807 【模板】卢卡斯定理

https://www.luogu.com.cn/problem/P3807

卢卡斯定理

用于求解\(n,m\)较大和\(n \ge p\)的情况

结论\(1\):对于\(k \in [1,p-1]\),有\({p \choose k} \equiv 0 (\mod p)\)

证明:

\[ {p \choose k}=\frac{p!}{k!(p-k)!}\\ =\frac{p}{k} \times \frac{(p-1)!}{(k-1)![(p-1)-(k-1)]!}\\ =\frac{p}{k} \times {p-1 \choose k-1}\\ \because p \in prime,k<p\\ \therefore \gcd(k,p)=1\\ \therefore \frac{p}{k} \times {p-1 \choose k-1} \equiv 0 (\mod p) \]

结论\(2\)\((1+k)^p \equiv k^p+1 (\mod p)\)

证明:

\[(1+k)^p=1+\sum_{i=1}^{p-1} {p \choose i} k^i+k^p \equiv 1+k^p (\mod p) \]

\(n=ap+b(0 \le b<p)\),\(m=cp+d(0\le d<p)\)

\[(1+k)^n=(1+k)^{ap} \times (1+k)^b \\ =(1+k^p)^a \times (1+k)^b\\ =(\sum_{i=0}^a {a \choose i}k^{ip}) \times (\sum_{j=0}^b {b \choose j}k^{j}) \]

我们从\(\sum_{i=0}^a {a \choose i}k^{ip}\)中抽取\(k^{cp}\),从\(\sum_{j=0}^b {b \choose j}k^{j}\)中抽取\(k^d\)

得到公式:

\[{n \choose m} (\mod p)=\\ \]

\[{\lfloor \frac{n}{p} \rfloor \choose \lfloor \frac{m}{p} \rfloor } {n \mod p \choose m \mod p} \]

即卢卡斯定理

\(C++ Code:\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 200005
#define ll long long
using namespace std;
int T,n,m,p;
ll jc[N],invjc[N];
ll ksm(ll x,ll y)
{
    ll ans=1;
    while (y)
    {
        if (y & 1)
            ans=ans*x%p;
        x=x*x%p;
        y >>=1;
    }
    return ans;
}
#define inv(x) (ksm(x,p-2))
#define C(n,k) (jc[n]*invjc[k]%p*invjc[n-k]%p)
ll Lucas(int n,int m,int p)
{
    if (!n||!m)
        return 1;
    return Lucas(n/p,m/p,p)*C(n%p,m%p)%p;
}
int main()
{
    scanf("%d",&T);
    while (T --> 0)
    {
        scanf("%d%d%d",&n,&m,&p);
        n+=m;
        jc[0]=1;
        for (int i=1;i<=n;i++)
            jc[i]=jc[i-1]*(ll)i%p;
        for (int i=0;i<=n;i++)
            invjc[i]=inv(jc[i]);
        printf("%lld\n",Lucas(n,m,p));
    }
    return 0;
}
posted @ 2020-07-29 19:53  GK0328  阅读(92)  评论(0编辑  收藏  举报