概述:
(Lucas) 定理用于求解大组合数取模的问题,其中 (p) 必须为素数。
(Lucas) 定理内容如下:
[C_{n}^{m}=C_{(n/p)}^{(m/p)} * C_{(n\%p)}^{(m\%p)}(mod p)
]
观察上述表达式,可知 (n\%p)和 (m\%p) 一定是小于 (p) 的数,可以直接求解。
(C_{(n/p)}^{(m/p)}) 可以继续用 (Lucas) 定理求解,这也就要求 (p) 的范围不能够太大,一般在 (1e5) 左右。
边界条件:当 (m=0) 的时候,返回 (1) 。
复杂度:(O(logn+p))
模板代码【P3807】:
//1≤n,m,p≤10^5,1≤T≤10,p为素数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll power(ll a,ll b,ll p)
{
ll res=1;
while(b)
{
if(b&1)
res=res*a%p;
a=a*a%p;
b>>=1;
}
return res%p;
}
ll C(ll n,ll m,ll p)
{
if(m>n)
return 0;
ll a=1,b=1;
m=min(m,n-m);
while(m)
{
a=a*(n-m+1)%p;
b=b*m%p;
m--;
}
return a*power(b,p-2,p);
}
ll Lucas(ll n,ll m,ll p)
{
return m?C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p:1;
}
int main()
{
int t;
scanf("%d",&t);
ll n,m,p;
while(t--)
{
scanf("%lld%lld%lld",&n,&m,&p);
printf("%lld
",Lucas(n+m,m,p));
}
return 0;
}