P4720 模板扩展卢卡斯定理/exLucas(无讲解,纯记录模板)
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4720 模板扩展卢卡斯定理/exLucas(无讲解,纯记录模板)相关的知识,希望对你有一定的参考价值。
题意:
C
n
m
m
o
d
p
C_{n}^{m}\\bmod p
Cnmmodp
对于 100% 的数据,1≤m≤n≤1018,2≤p≤106,不保证 p 是质数。
题解:
模板题,单纯写本文章记录板子
代码:
#include <cstdio>
using namespace std;
typedef long long ll;
ll mod;
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 n, ll p)
{
ll x, y;
exgcd(n, p, x, y);
return (x + p) % p;
}
ll qpow(ll base, ll p, ll mod)
{
ll ret= 1;
for (; p; p>>= 1, base= base * base % mod)
if (p & 1)
ret= ret * base % mod;
return ret;
}
ll CRT(int n, ll* a, ll* m)
{
ll M= 1, ret= 0;
for (ll i= 1; i <= n; i++)
M*= m[i];
for (ll i= 1; i <= n; i++) {
ll w= M / m[i];
ret= (ret + a[i] * w % mod * inv(w, m[i]) % mod) % mod;
}
return (ret + mod) % mod;
}
ll calc(ll n, ll q, ll qk)
{
if (!n)
return 1;
ll ret= 1;
for (ll i= 1; i <= qk; i++)
if (i % q)
ret= ret * i % qk;
ret= qpow(ret, n / qk, qk);
for (ll i= n / qk * qk + 1; i <= n; i++)
if (i % q)
ret= ret * (i % qk) % qk;
return ret * calc(n / q, q, qk) % qk;
}
ll multiLucas(ll n, ll m, ll q, ll qk)
{
int cnt= 0;
for (ll i= n; i; i/= q)
cnt+= i / q;
for (ll i= m; i; i/= q)
cnt-= i / q;
for (ll i= n - m; i; i/= q)
cnt-= i / q;
return qpow(q, cnt, qk) * calc(n, q, qk) % qk * inv(calc(m, q, qk), qk) % qk * inv(calc(n - m, q, qk), qk) % qk;
}
ll exLucas(ll n, ll m, ll p)
{
int cnt= 0;
ll qk[20], a[20]; //存放所有的 q^k 和待合并答案的结果
for (ll i= 2; i * i <= p; ++i) //质因数分解
{
if (p % i == 0) {
qk[++cnt]= 1;
while (p % i == 0)
qk[cnt]*= i, p/= i;
a[cnt]= multiLucas(n, m, i, qk[cnt]);
}
}
if (p > 1)
qk[++cnt]= p, a[cnt]= multiLucas(n, m, p, p);
return CRT(cnt, a, qk); //CRT 合并答案
}
int main()
{
ll n, m, p;
scanf("%lld %lld %lld", &n, &m, &p);
mod= p;
printf("%lld\\n", exLucas(n, m, p));
return 0;
}
以上是关于P4720 模板扩展卢卡斯定理/exLucas(无讲解,纯记录模板)的主要内容,如果未能解决你的问题,请参考以下文章
[模板] 数学基础:逆元/exGCD/exCRT/Lucas定理/exLucas