Link
Luogu - https://www.luogu.org/problemnew/show/P3807
n
,
m
n,m
n,m 为正整数,
p
p
p 为质数 那么
(
n
m
)
%
p
=
[
(
n
%
p
m
%
p
)
%
p
]
∗
[
(
n
/
p
m
/
p
)
%
p
]
%
p
\binom{n}{m}\%p=\left[\binom{n\%p}{m\%p}\%p\right]*\left[\binom{n/p}{m/p}\%p\right]\%p
(mn)%p=[(m%pn%p)%p]∗[(m/pn/p)%p]%p
时间复杂度如果算上预处理是
O
(
p
)
O(p)
O(p)
单次查询
O
(
log
p
)
O(\log_p)
O(logp) 左右?
另外一个常用的东西
线性求逆元
A[i] = (p - p / i) * A[p % i];
证明参考
p
=
k
i
+
r
p=ki+r
p=ki+r
k
i
+
r
≡
0
(
m
o
d
p
)
ki+r\equiv0\pmod{p}
ki+r≡0(modp)
k
r
−
1
≡
−
i
−
1
(
m
o
d
p
)
kr^{-1}\equiv-i^{-1}\pmod{p}
kr−1≡−i−1(modp)
i
−
1
≡
−
⌊
p
i
⌋
⋅
r
−
1
(
m
o
d
p
)
i^{-1}\equiv-\lfloor\frac{p}{i}\rfloor\cdot r^{-1}\pmod{p}
i−1≡−⌊ip⌋⋅r−1(modp)
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN = 1e5+5;
int T, n, m, p, stair[MAXN], rev[MAXN], inv[MAXN];
inline int C(const int& n, const int& m)
{
if (m > n) return 0;
return 1ll * stair[n] * rev[m] % p * rev[n-m] % p;
}
int Lucas(const int& n, const int& m, const int& p)
{
if (!m) return 1;
return 1ll * Lucas(n/p, m/p, p) * C(n%p, m%p) % p;
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &m, &p);
inv[0] = 0;
stair[0] = stair[1] = inv[1] = rev[0] = rev[1] = 1;
for (register int i = 2; i < p; ++i) stair[i] = 1ll * stair[i-1] * i % p;
for (register int i = 2; i < p; ++i) inv[i] = 1ll * (p - p / i) * inv[p % i] % p;
for (register int i = 2; i < p; ++i) rev[i] = 1ll * rev[i-1] * inv[i] % p;
printf("%d\n", Lucas(n + m, m, p));
}
return 0;
}