,
不为素数
首先对p进行因式分解,
然后用中国剩余定理合并
现在的问题是怎么求出
因为、
不一定和
互质, 所以
、
的逆元不一定存在
因此我们可以化简一下
,这样形如
与
一定互质,逆元一定存在
那我们怎么计算, 我们可以先计算
为了方便理解,我们先假设
因为我们要保证互质,逆元才存在,所以要被除掉
我们定义
,那么现在就可以求逆元了
接下来讲解如何求解指数
我们令 ,显然
是我们需要的指数,但是
可能还有
的倍数
所以,
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll power(ll a, ll b, ll n) // 快速幂
{
a %= n;
ll ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % n;
a = (a * a) % n;
b >>= 1;
}
return ans;
}
ll exgcd(ll a, ll b, ll &x, ll &y) // 扩展欧几里得
{
if(b == 0) {
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll t = x;
x = y;
y = t - a / b * y;
return d;
}
ll inverse(ll a, ll p) // 逆元
{
ll x, y;
exgcd(a, p, x, y);
x = (x % p + p) % p;
return x;
}
ll CRT(ll *a, ll *m, ll n) // 中国剩余定理
{
ll M = 1, ans = 0, x, y;
for(ll i = 1; i <= n; i++) M *= m[i];
for(ll i = 1; i <= n; i++) {
ll w = M / m[i];
exgcd(w, m[i], x, y);
x = (x % m[i] + m[i]) % m[i];
ans = (ans + (a[i] % M + M) % M * w % M * x % M) % M;
}
return (ans % M + M) % M;
}
ll calc(ll n, ll x, ll p) // n! mod p
{
if(n == 0) return 1;
ll s = 1;
for(ll i = 2; i <= p; i++) if(i % x) s = s * i % p;
s = power(s, n / p, p);
for(ll i = 2; i <= n % p; i++) if(i % x) s = s * i % p;
return s * calc(n / x, x , p) % p;
}
ll multilucas(ll n, ll m, ll x, ll p) //
{
ll cnt = 0;
for(ll i = n; i; i /= x) cnt += i / x;
for(ll i = m; i; i /= x) cnt -= i / x;
for(ll i = n-m; i; i /= x) cnt -= i / x;
return power(x, cnt, p) % p * calc(n, x, p) % p
* inverse(calc(m, x, p), p) % p * inverse(calc(n-m, x, p), p) % p;
}
ll exlucas(ll n, ll m, ll p) //扩展Lucas
{
ll cnt = 0;
ll prime[100], a[100];
for(ll i = 2; i * i <= p; i++) {
if(p % i == 0) {
prime[++cnt] = 1;
while(p % i == 0) prime[cnt] *= i, p /= i;
a[cnt] = multilucas(n, m, i, prime[cnt]);
}
}
if(p > 1) prime[++cnt] = p, a[cnt] = multilucas(n, m, p, p);
return CRT(a, prime, cnt);
}
int main()
{
ll n, m, p;
while(scanf("%lld %lld %lld", &n, &m, &p) == 3) {
printf("%lld\n", exlucas(n, m, p));
}
return 0;
}