卧薪尝胆,厚积薄发。
扩展卢卡斯定理
Date: Mon Jul 02 00:43:03 CST 2018
In Category:
总结
卢卡斯定理
$C_n^m\ mod\ p=C_{n/p}^{m/p}\times C_{n\%p}^{m\%p}\ mod\ p$
可以看作是将
$n$
和
$m$
用
$p$
进制分解,对于每一位分别求组合数再乘起来。
扩展卢卡斯定理
由于求组合数时需要用到除法,如果
$p$
不为质数可能不存在逆元,这时卢卡斯定理不成立。
扩展卢卡斯定理将
$p$
分解成
$p=p_1^{q_1}\times p_2^{q_2}\times \cdots \times p_m^{q_m}$
的形式,计算
$C_n^m$
对每个
$p_i^{q_i}$
分别取模的值再用中国剩余定理合并。
对于模
$p_i^{q_i}$
时,将阶乘中的
$p_i$
的倍数提出来用快速幂单独计算,一个阶乘提出
$p_i$
的倍数再除掉
$p_i$
后仍然是一个阶乘,于是可用三个循环得到
$p_i$
的指数。
for(ll i = n;i > 0;i /= p)c += i / p;
for(ll i = m;i > 0;i /= p)c -= i / p;
for(ll i = n - m;i > 0;i /= p)c -= i / p;
去掉所有
$p$
的倍数后与模数互质,可以求逆元,在求逆元时由于每
$p_i^{q_i}$
循环一次,所以可以只计算出
$\begin{align}(\Pi_{i=2}^{p_i^{q_i}}i)^{\lfloor\frac n p\rfloor}\times\Pi_{i=2}^{n\%p_i^{q_i}}i\ mod\ p_i^{q_i}\end{align}$
,由于在前一步中提出来了一个
$p_i$
的指数,而这一步计算了
$p_i$
的倍数,
$p_i$
的倍数除去指数剩下的还是一个阶乘,范围为
$1$
~
$\lfloor\frac n p\rfloor$
,可以递归计算。
ll tot = 0,divi[100000],times[100000];
ll sumw = 0;
void dev()
{
ll k = MOD;
for(ll i = 2;i <= k;++i)
{
if(k % i == 0)
{
divi[++tot] = i;
times[tot] = 1;
while(k % i == 0)
{
times[tot] *= i;
k /= i;
}
}
}
return;
}
ll power(ll a,ll b,ll mod)//a ^ b % mod
{
ll res = 1;
while(b > 0)
{
if(b & 1)res = res * a % mod;
a = a * a % mod;
b = b >> 1;
}
return res;
}
ll fac(ll n,ll p,ll pr)//n! % pr
{
if(n == 0)return 1;
ll res = 1;
for(ll i = 2;i <= pr;++i)
{
if(i % p != 0)
{
res = res * i % pr;
}
}
res = power(res,n / pr,pr);
ll r = n % pr;
for(ll i = 2;i <= r;++i)
{
if(i % p != 0)
{
res = res * i % pr;
}
}
res = res * fac(n / p,p,pr) % pr;
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y)//ax + by = gcd(a,b)
{
if(b == 0)
{
x = 1;y = 0;
return a;
}
ll t = exgcd(b,a % b,x,y);
ll k = x;
x = y;
y = k - (a / b) * y;
return t;
}
ll inv(ll a,ll n)//a * a^{-1} = 1 (mod n)
{
ll x,y;
ll t = exgcd(a,n,x,y);
x = (x % n + n) % n;
return x;
}
ll lucas(ll n,ll m,ll p,ll pr)
{
if(n < m)return 0;
ll c = 0;
for(ll i = n;i > 0;i /= p)c += i / p;
for(ll i = m;i > 0;i /= p)c -= i / p;
for(ll i = n - m;i > 0;i /= p)c -= i / p;
ll res = fac(n,p,pr) * inv(fac(m,p,pr),pr) % pr * inv(fac(n - m,p,pr),pr) % pr * power(p,c,pr) % pr;
return res;
}
ll CRT(ll n,ll m)
{
ll ans = 0;
for(int i = 1;i <= tot;++i)
{
ans = (ans + lucas(n,m,divi[i],times[i]) * inv(MOD / times[i],times[i]) % MOD * (MOD / times[i]) % MOD) % MOD;
}
return ans;
}
In tag:
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡