试例输出为0,呜呜呜,求助!!!
查看原帖
试例输出为0,呜呜呜,求助!!!
959579
xiaobu_dean楼主2023/10/15 18:34
// 给定a,b,p求c(a,b)mod p,a,b <= 1e18,p <= 1e5,且p为质数
// 当a,b > p时,a,b与p就不互质了,那么无法通过费马小定理求逆元的方式求组合数了
// 卢卡斯定理:c(a,b)mod p = c(a/p,b/p) * c(a%p,b%p) % p
// 1.首先对于c(a%p,b%p),a%p,b%p一定小于p,p为质数,所以a%p,b%p一定与p互质,我们就可以用费马小定理求逆元的方法求
// 2.对于c(a/p,b/p)来说,a/p,b/p不一定小于p,所以我们继续调用卢卡斯定理求,这时a = a/p,b = b/p
#include <bits/stdc++.h>
using namespace std;

using ll = long long ;
const int N = 1e5 + 50;
ll fac[N]; // 阶乘
ll divfac[N]; // 阶乘的逆元
ll ksm(ll a,ll b,ll p) {
	ll ret = 1;
	while (b) {
		if (b & 1) ret = ret  * a % p;
		a = a * a % p ;
		b >>= 1;
	}
	return ret % p;
}
void init(ll p) { // 由于每组的p不同所以分开处理
	fac[0] = divfac[0] = 1;
	for (int i = 1;i <= 1e5; i++) {
		fac[i] = fac[i - 1] * i % p;
		divfac[i] = divfac[i - 1] * ksm(i,p - 2,p) % p;
	}
}

ll getc(ll a,ll b,ll p) { // 通过快速幂求c(a%p,b%p)
	if (b > a) return 0;
	return fac[a] % p * divfac[b] % p * divfac[a - b] % p;
}

ll lucas(ll a,ll b,ll p) { // c(a%p,b%p) * c(a/p,b/p) % p
	if (b == 0) return 1;
	return getc(a%p,b%p,p) * lucas(a/p,b/p,p) % p;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
    int n; cin >> n;
    while (n--) {
    	ll a,b,p; cin >> a >> b >> p;
    	init(p); // 先打一下表
        ll ans = lucas(a,a + b,p);
        cout << ans << '\n';
    }
	return 0;
}
2023/10/15 18:34
加载中...