#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int N = 1000;
ll B[N], P[N];
inline ll qpow(ll a, ll b, ll p) {
ll res = 1; a %= p;
while (b) {
if (b & 1LL) {
res = (res * a) % p;
}
a = (a * a) % p;
b >>= 1LL;
}
return res;
}
inline void exgcd(ll a, ll b, ll& x, ll& y) {
if (!b) {
x = 1, y = 0; return; }
exgcd(b, a % b, y, x);
y -= a / b * x;
return;
}
inline ll inv(ll a, ll p) {
ll x, y; exgcd(a, p, x, y);
return (x % p + p) % p;
}
inline ll f(ll n, ll p, ll pk) {
if (n == 0) return 1;
ll rou = 1, rem = 1;
//rou : 循环节 rem : 余项
for (ll i = 1; i <= pk; i++) {
if (i % p) rou = (rou * i) % pk;
}
rou = qpow(rou, n / pk, pk);
for (ll i = (n / pk) * pk; i <= n; i++) {
if (i % p) rem = (rem * (i % pk) % pk);
}
return f(n / p, p, pk) * rou % pk * rem % pk;
}
inline ll g(ll n, ll p) {
ll res = 0;
while (n / p) {
res += n / p;
n /= p;
}
return res;
}
inline ll CPk(ll n, ll m, ll p, ll pk) {
ll up = f(n, p, pk);
ll down1 = inv(f(m, p, pk), pk);
ll down2 = inv(f(n - m, p, pk), pk);
ll pg = qpow(p, g(n, p) - g(m, p) - g(n - m, p), pk);
return (((up * down1) % pk * down2) % pk * pg) % pk;
}
inline ll exlucas(ll n, ll m, ll p) {
ll mul = p, cnt = 0;
for (ll i = 2; i * i <= p; i++) {
if (!(p % i)) {
ll pk = 1;
while (!(p % i)) {
p /= i, pk *= i;
}
P[++cnt] = pk, B[cnt] = CPk(n, m, i, pk);
}
}
if (p >= 2) {
P[++cnt] = p, B[cnt] = CPk(n, m, p, p); }
ll sum = 0;
for (ll i = 1; i <= cnt; i++) {
ll t = mul / P[i];
sum = (sum + t % mul * B[i] % mul * inv(t, P[i])) % mul;
}
return sum % mul;
}
int main() {
ll n, m, p;
cin >> n >> m >> p;
printf("%lld\n", exlucas(n, m, p));
return 0;
}
Template-exLucas (modulo large number of combinations)
Guess you like
Origin blog.csdn.net/qq_45739057/article/details/108531577
Recommended
Ranking