【Gym 100633J】Ceizenpok’s formula 扩展Lucas详解

C_n^m \ mod \ pp 不为素数

首先对p进行因式分解,p = p_1^{a_1}p_2^{a_2}p_3^{a_3}...p_n^{a_n}

然后用中国剩余定理合并

 \left \{ \begin{matrix} C_n^m\ mod \ p_1^{a_1}\\ C_n^m\ mod \ p_2^{a_2}\\ ...\\ C_n^m\ mod \ p_n^{a_n}\\ \end{matrix}

现在的问题是怎么求出 C_n^m\ mod\ p^t

C_n^m\ mod\ p^t = \frac{n!}{m!(n-m)!}\ mod \ p^t

因为m!(n - m)! 不一定和 p^t 互质, 所以m!(n - m)! 的逆元不一定存在

因此我们可以化简一下

\frac{\frac{n!}{p^x}} {\frac{m!}{p^y} \frac{(n-m)!}{p^z}}\ p^{x-y-z}\ mod \ p^t,这样形如\frac{n!}{p^x}与 p^t一定互质,逆元一定存在

那我们怎么计算\frac{n!}{p^x}\ mod \ p^t, 我们可以先计算n!\ mod\ p^t

为了方便理解,我们先假设n = 22, p = 3, t = 2

22!

=(1\cdot2\cdot3\cdot4\cdot5\cdot6\cdot7\cdot8\cdot9\cdot10\cdot11\cdot12\cdot13\cdot14\cdot15\cdot16\cdot17\cdot18\cdot19\cdot20\cdot21) \ mod \ 3^2 

=(1\cdot2\cdot4\cdot5\cdot7\cdot8)(10\cdot11\cdot13\cdot14\cdot16\cdot17)(19\cdot20\cdot22)(3\cdot6\cdot9\cdot12\cdot15\cdot18\cdot21)

=3^7\cdot7!(1\cdot2\cdot4\cdot5\cdot7\cdot8)^2(19\cdot20\cdot22)\ mod \ 3^2

n! \ mod \ p^t = p^{\left \lfloor \frac{n}{p} \right \rfloor}\left \lfloor \frac{n}{p} \right \rfloor!{(\sum_{i=1,i \not\equiv 0\ mod\ p}^{p^t} i)}^{\left \lfloor \frac{n}{p^t} \right \rfloor}({\sum_{i = \left \lfloor \frac{n}{p^t} \right \rfloor p^t , i \not\equiv 0\ mod\ p^t }^n i})

因为我们要保证互质,逆元才存在,所以p^{\left \lfloor \frac{n}{p} \right \rfloor}要被除掉

我们定义f(n) = \frac{n!}{p^x}

f(n) = f(\left \lfloor \frac{n}{p} \right \rfloor){(\sum_{i=1,i \not\equiv 0\ mod\ p}^{p^t} i)}^{\left \lfloor \frac{n}{p^t} \right \rfloor}({\sum_{i = \left \lfloor \frac{n}{p^t} \right \rfloor p^t , i \not\equiv 0\ mod\ p^t }^n i})

\frac{\frac{n!}{p^x}} {\frac{m!}{p^y} \frac{(n-m)!}{p^z}}\ p^{x-y-z}\ mod \ p^t

= \frac{f(n)}{f(m)f(n-m)}p^{x-y-z} \ mod\ p^t,那么现在就可以求逆元了

接下来讲解如何求解指数

n! \ mod \ p^t = p^{\left \lfloor \frac{n}{p} \right \rfloor}\left \lfloor \frac{n}{p} \right \rfloor!{(\sum_{i=1,i \not\equiv 0\ mod\ p}^{p^t} i)}^{\left \lfloor \frac{n}{p^t} \right \rfloor}({\sum_{i = \left \lfloor \frac{n}{p^t} \right \rfloor p^t , i \not\equiv 0\ mod\ p^t }^n i})

我们令 g(n) = x,显然 p^{\left \lfloor \frac{n}{p} \right \rfloor} 是我们需要的指数,但是 \left \lfloor \frac{n}{p} \right \rfloor!可能还有 p 的倍数

所以,  g(n) = \left \lfloor \frac{n}{p} \right \rfloor + g(\left \lfloor \frac{n}{p} \right \rfloor )

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll power(ll a, ll b, ll n)  // 快速幂
{
	a %= n;
	ll ans = 1;
	while(b) {
		if(b & 1) ans = (ans * a) % n;
		a = (a * a) % n;
		b >>= 1;
	}
	return ans;
}
ll exgcd(ll a, ll b, ll &x, ll &y) // 扩展欧几里得
{
	if(b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, x, y);
	ll t = x;
	x = y;
	y = t - a / b * y;
	return d;
}
ll inverse(ll a, ll p)  // 逆元
{
	ll x, y;
	exgcd(a, p, x, y);
	x = (x % p + p) % p;
	return x;
}
ll CRT(ll *a, ll *m, ll n) // 中国剩余定理
{
	ll M = 1, ans = 0, x, y;
	for(ll i = 1; i <= n; i++) M *= m[i];
	for(ll i = 1; i <= n; i++) {
		ll w = M / m[i];
		exgcd(w, m[i], x, y);
		x = (x % m[i] + m[i]) % m[i];
		ans = (ans + (a[i] % M + M) % M * w % M * x % M) % M;
	}
	return (ans % M + M) % M;
}
ll calc(ll n, ll x, ll p)  // n! mod p
{
	if(n == 0) return 1;
	ll s = 1;
	for(ll i = 2; i <= p; i++) if(i % x) s = s * i % p;
	s = power(s, n / p, p);
	for(ll i = 2; i <= n % p; i++) if(i % x) s = s * i % p;
	return s * calc(n / x, x , p) % p;
}
ll multilucas(ll n, ll m, ll x, ll p)  //
{
	ll cnt = 0;
	for(ll i = n; i; i /= x) cnt += i / x;
	for(ll i = m; i; i /= x) cnt -= i / x;
	for(ll i = n-m; i; i /= x) cnt -= i / x;
	return power(x, cnt, p) % p * calc(n, x, p) % p
		   * inverse(calc(m, x, p), p) % p * inverse(calc(n-m, x, p), p) % p;
}
ll exlucas(ll n, ll m, ll p)  //扩展Lucas
{
	ll cnt = 0;
	ll prime[100], a[100];
	for(ll i = 2; i * i <= p; i++) {
		if(p % i == 0) {
			prime[++cnt] = 1;
			while(p % i == 0) prime[cnt] *= i, p /= i;
			a[cnt] = multilucas(n, m, i, prime[cnt]);
		}
	}
	if(p > 1) prime[++cnt] = p, a[cnt] = multilucas(n, m, p, p);
	return CRT(a, prime, cnt);
}
int main()
{
	ll n, m, p;
	while(scanf("%lld %lld %lld", &n, &m, &p) == 3) {
		printf("%lld\n", exlucas(n, m, p));
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值