卢卡斯定理/Lucas 定理【模板】

>Link

luogu P3807


>解题思路

(早上打比赛写不出来的时候去洛谷看了下lucas

C m n m o d p C^n_mmodp Cmnmodp 1 ≤ n , m , p ≤ 1 0 5 1≤n,m,p≤10^5 1n,m,p105

因为 p p p质数(太爱质数啦),所以 ( p j ) ≡ 0 ( m o d p ) \binom{p}{j}\equiv 0(modp) (jp)0(modp)
通过化简可以得到 ( 1 + j ) p = ∑ i = 0 p ( p i ) ∗ j i (1+j)^p=\sum_{i=0}^{p}\binom{p}{i}*j^i (1+j)p=i=0p(ip)ji
( 1 + j ) p = 1 + ∑ i = 1 p − 1 ( p i ) ∗ j i + j p ≡ 1 + j p ( m o d p ) (1+j)^p=1+\sum_{i=1}^{p-1}\binom{p}{i}*j^i+j^p\equiv 1+j^p(modp) (1+j)p=1+i=1p1(ip)ji+jp1+jp(modp)

n = s p + q , m = l p + r n=sp+q,m=lp+r n=sp+q,m=lp+r ( q < r ) (q<r) (q<r)
所以 ( 1 + x ) s p + q = ( 1 + x ) s p ∗ ( 1 + x ) q ≡ ( 1 + x p ) s ∗ ( 1 + x ) q (1+x)^{sp+q}=(1+x)^{sp}*(1+x)^q\equiv (1+x^p)^s*(1+x)^q (1+x)sp+q=(1+x)sp(1+x)q(1+xp)s(1+x)q
( 1 + x ) s p + q ≡ ( ∑ i = 0 s ( s i ) x p i ) ∗ ( ∑ i = 0 q ( q i ) x i ) (1+x)^{sp+q}\equiv (\sum _{i=0}^{s}\binom{s}{i}x^{pi})*(\sum _{i=0}^{q}\binom{q}{i}x^{i}) (1+x)sp+q(i=0s(is)xpi)(i=0q(iq)xi)

因为 p p p是质数(太爱质数啦),所以两边可以同时约去 x m x^m xm
( n m ) ∗ x m ≡ ( s l ) ∗ x l p ∗ ( q r ) ∗ x r ≡ ( s l ) ∗ ( q r ) \binom{n}{m}*x^m\equiv \binom{s}{l}*x^{lp}*\binom{q}{r}*x^r\equiv \binom{s}{l}*\binom{q}{r} (mn)xm(ls)xlp(rq)xr(ls)(rq)

所以
C ( n m ) ≡ C ( ⌊ n / p ⌋ ⌊ m / p ⌋ ) ∗ C ( n m o d p m m o d p ) ( m o d p ) {\color{Red} C\binom{n}{m}\equiv C\binom{\left \lfloor n/p \right \rfloor}{\left \lfloor m/p \right \rfloor}*C\binom{nmodp}{m modp}(modp)} C(mn)C(m/pn/p)C(mmodpnmodp)(modp)

PS:组合数里面有除法,所以要用逆元


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

int T;
LL p;

LL power (LL a, LL b)
{
	a %= p;
	LL ret = 1;
	for (; b; b >>= 1, a = a * a % p)
	  if (b & 1) ret = ret * a % p;
	return ret;
}
LL C (LL a, LL b)
{
	if (a < b) return 0; //一定要加!!!
	LL ret = 1;
	for (LL i = b + 1; i <= a; i++) ret = ret * (i % p) % p;
	for (LL i = 1; i <= a - b; i++) ret = ret * power (i, p - 2) % p;
	return ret;
}
LL lucas (LL n, LL m)
{
	return C (n % p, m % p) * C (n / p, m / p) % p;
}

int main()
{
	LL n, m;
	scanf ("%d", &T);
	while (T--)
	{
		scanf ("%lld%lld%lld", &n, &m, &p);
		printf ("%lld\n", lucas (n + m, n));
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值