卢卡斯定理自我感觉感性理解比堆式子更能然人静下心来看
我的大部分式子都是展开形式就是一堆没有的展开
首先我们需要证明(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)
( herefore (1+x)^a equiv (1+x^p)^l cdot (1+x)^r)
观察项(x^b)的系数
(ecause C_a^bx^b equiv C_l^sx^{sp} cdot C_r^jx^j)
( herefore C_a^bx^b equiv C_l^s cdot C_r^jx^b)
( herefore C_a^bequiv C_l^scdot C_r^j equiv C_{lfloor frac{a}{p} floor}^{lfloor frac{b}{p} floor}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
",lucas(n+m,m));
}
}