卢卡斯定理自我感觉感性理解比堆式子更能然人静下心来看
我的大部分式子都是展开形式就是一堆没有的展开
首先我们需要证明\(C_p^i=\frac{p}{j}C_{p-1}^{i-1}\equiv0~~~(mod~p),(1<=i<=p-1)\)
\(C_p^i=\frac{p!}{i!(p-i)!}=\frac{p}{i} \frac{(p-1)!}{(i-1)!(p-1-i+1)!}= \frac{p}{i} \frac{(p-1)!}{(i-1)!(p-i)!}=\frac{p}{j}C_{p-1}^{i-1}\)
得证。
然后根据这种性质和二项式定理。,我们马上得出鬼嘞!!
\((1+x)^p=C_p^01^p+C_p^1x^{2}+....+C_p^px^p=C_p^01^px^0+C_p^p1^0x^p=1+x^p\)
然后我们接下来要求证
\(C_a^b=C_{a_0}^{b_0}\cdot C_{a_1p}^{b_1p} \cdot C_{a_2p^2}^{b_2p^2}.....\)
其实我们令\(a=lp+r,b=sp+j\)好奇怪的变量名呀
求证\(C_a^b=C_{lp}^{sp}\cdot C_{r}^{j}\)然后利用性质递归求解就可以了。
继续从二次项定理出发
\((1+x)^a=(1+x)^{lp} \cdot (1+x)^r\)
然后展开\((1+x)^{lp}\)
\((1+x)^{lp} \equiv ((1+x)^p)^l \equiv (1+x^p)^l\)
\(\therefore (1+x)^a \equiv (1+x^p)^l \cdot (1+x)^r\)
观察项\(x^b\)的系数
\(\because C_a^bx^b \equiv C_l^sx^{sp} \cdot C_r^jx^j\)
\(\therefore C_a^bx^b \equiv C_l^s \cdot C_r^jx^b\)
\(\therefore C_a^b\equiv C_l^s\cdot C_r^j \equiv C_{\lfloor \frac{a}{p} \rfloor}^{\lfloor \frac{b}{p} \rfloor}\cdot C_{a~mod~p}^{b~mod~p}\)
上面的下取整是计算l and s,mod 是为了计算 r and j
得证
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
long long base[101000],mod;
long long kasumi(long long n,long long m)//利用费马小定理求解逆元
{
long long res=1;
while(m)
{
if(m&1) res=(res*n)%mod;
m>>=1;
n=(n*n)%mod;
}
return res;
}
long long C(long long n,long long m)
{
if(n<m) return 0;
int res=(base[n]*kasumi(base[m],mod-2)*kasumi(base[n-m],mod-2))%mod;
return res;
}
long long lucas(long long n,long long m)
{
if(n<m) return 0;
if(!n) return 1;
return (lucas(n/mod,m/mod)*C(n%mod,m%mod))%mod;
}
int main()
{
base[0]=1;
long long n,m;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&mod);
for(int i=1;i<=n+m;i++)
base[i]=(base[i-1]*i)%mod;
printf("%lld\n",lucas(n+m,m));
}
}