lucas定理
先預先求出.
並利用費馬小定理和快速冪乘求出每一個的逆元。求,當直接就是.若都在範圍內,則直接轉化爲.否則就是lucas定理縮小規模。
[對一個固定的p,預處理求階乘及快速模冪求其逆元,時間複雜度。空間複雜度。預處理之後,單次求複雜度]{}
洛谷P3807模板題
void prepare(ll p, vector<ll>&fac, vector<ll>&inv_fac) {
fac.resize(p); inv_fac.resize(p);
mod_sys mod;
mod.set_mod(p);
fac[0] = 1;
inv_fac[0] = 1;
for (int i = 1; i < p; ++i) {
fac[i] = (fac[i-1]*i)%p;
inv_fac[i] = mod.pow(fac[i], p-2); // 既然能枚舉一遍,p*p不應該爆ll
}
}
// 輸入預設0=<n,m<p
inline ll combination(ll n, ll m, ll p, vector<ll>&fac, vector<ll>&inv_fac) {
if (n < m) return 0;
return fac[n]*inv_fac[m]%p*inv_fac[n-m]%p;
}
ll lucas(ll n, ll m, ll p, vector<ll>&fac, vector<ll>&inv_fac) {
if (n < m) return 0;
ll ans = 1;
while(true) {
if (m == 0) return ans;
if (n < p && m < p) return ans*combination(n,m,p,fac,inv_fac)%p;
ans = ans * combination(n%p,m%p,p,fac,inv_fac)%p;
n/=p; m/=p;
}
}