【模板】扩展卢卡斯定理(仅代码纯享版)

#include<cstdio>
#define LL long long

using namespace std;

const int MAX = 1e6 + 10;
LL n, m, p, tot;
LL a[MAX], r[MAX];

LL exgcd(LL a, LL b, LL &x, LL &y){//扩展欧几里得 
	if(!b){
		x = 1;
		y = 0;
		return a;
	}
	
	LL s = exgcd(b, a % b, x, y);
	LL t = x;
	x = y;
	y = t - a / b * y;
	
	return s;
}

LL Inv(LL a, LL p){//逆元 
	LL x,y;
	
	exgcd(a, p, x, y);
	
	return (x + p) % p;
}

LL Fast_pow(LL a, LL w, LL p){//快速幂  
	LL ans = 1;
	
	while(w){
		if(w & 1) ans = ans * a % p;
		a = a * a % p;
		w >>= 1;
	}
	
	return ans;
}

LL Fac(LL n, LL p, LL w){//计算 n! % p ^ w 
	if(!n) return 1;
	
	LL cir = 1/*循环节*/, res = 1/*余数*/;
	for(register LL i = 1; i <= w; i++)
		if(i % p) cir = cir * i % w;
	cir = Fast_pow(cir, n / w, w);
	for(register LL i = w * (n / w); i <= n; i++)
		if(i % p) res = res * (i % w) % w;
		
	return Fac(n / p, p, w) * cir % w * res % w;
}

LL get_Sum(LL n, LL p){//求 n! 中有多少个 p 
	if(n < p) return 0;
	return get_Sum(n / p, p) + (n / p);
}

LL C(LL n, LL m, LL p, LL w){
	if(!m) return 1;
	else if(m > n) return 0;
	
	LL np = Fac(n, p, w), mp = Inv(Fac(m, p, w), w), nmp = Inv(Fac(n - m, p, w), w);
	LL mi = Fast_pow(p, get_Sum(n, p) - get_Sum(m, p) - get_Sum(n - m, p), w);
	
	return np * mp % w * nmp % w * mi % w;
}

void Div(LL n, LL m, LL p, LL *a, LL *r){//把 p 分解 
	LL w = p;

	for(register LL i = 2; i * i <= w; i++){
		LL tmp = 1;
		if(!(w % i)){
			while(!(w % i)){
				tmp *= i;
				w /= i;
			}
			a[++tot] = tmp;
			r[tot] = C(n, m, i, tmp);
		}
	} 
	
	if(w != 1){
		a[++tot] = w;
		r[tot] = C(n, m, w, w);
	}
}

LL Crt(LL n, LL p, LL *a, LL *r){
	LL ans = 0;

	for(register LL i = 1; i <= n; i++){
		LL s = p / a[i];
		LL x = Inv(s, a[i]);
		ans = (ans + r[i] * s % p * x % p) % p;
	}
	
	return ans;
}

LL exLucas(LL n, LL m, LL p){
	tot = 0; 
	Div(n, m, p, a, r);
	
	return Crt(tot, p, a, r);
}

int main(){
	scanf("%lld%lld%lld",&n,&m,&p);
	
	printf("%lld",exLucas(n, m, p));
	
	return 0;
}

例题

P4720 【模板】扩展卢卡斯定理/exLucas

P2183 [国家集训队]礼物

posted @ 2022-08-03 22:00  TSTYFST  阅读(30)  评论(0编辑  收藏  举报