lucas定理

求组合数模某个数的余数。注意一般的阶乘预处理组合数,虽然也能取模,如果出现的组合数 C ( n , m ) C(n,m) C(n,m),预处理复杂度就是 O ( n ) O(n) O(n)的,如果我们的组合数很大就完了

这时就需要lucas定理了,内容是这样,
在这里插入图片描述
第一项可以继续用lucas递归处理,第二项的系数都是模p之后的,所以我们预处理组合数,可以只用求出来不超过p的,预处理复杂度变成 O ( p ) O(p) O(p)了,会快很多。然后lucas本身的复杂度,由于一直在除 p p p递归,显然只有 O ( l o g n ) O(logn) O(logn),相比 O ( n ) O(n) O(n)预处理,在 n = 1 e 9 n=1e9 n=1e9甚至更大时显然快了很多,这就是lucas的优点

当然这也要求了模数 p p p不能太大,如果也 p = 1 e 9 p=1e9 p=1e9就没意义了

void solve(){
	int n,m,p;
	cin>>n>>m>>p;
	vi fa(p+1);
	fa[0]=1;
	rep(i,1,p){
		fa[i]=fa[i-1]*i%p;
	}
	auto C=[&](int n,int m,int p)->int{
		return fa[n]*power(fa[m],p-2,p)%p*power(fa[n-m],p-2,p)%p;
	};
	auto &&lucas=[&](auto &&lucas,int n,int m,int p)->int{
		if(m==0)return 1;	
		return C(n%p,m%p,p)*lucas(lucas,n/p,m/p,p)%p;
	};
	cout<<lucas(lucas,n+m,m,p)<<'\n';
}

可以看到Lucas也要预处理组合数,这里需要注意的是,由于p不大,可能出现阶乘的值是p的倍数,然后求逆元可能就会失败,所以我们不用求 i f a c ifac ifac了,只用求 f a c fac fac,需要逆元的时候用快速幂就行了

然后这里其实有一个推论,算组合数奇偶性的时候,可以直接`n&k==k,等价于 C ( n , k ) 模 2 = 1 C(n,k)模2=1 C(n,k)2=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值