求 ({n+m choose n}mod p)
卢卡斯(Lucas)定理
[{n choose m}equiv{nmod p choose mmod p} imes{lfloor{nover p}
floor choose lfloor{mover p}
floor}pmod p
]
证明(感谢Lance1ot)
首先我们需要证明
[{pchoose i}equiv{pover i}{p-1choose i-1}equiv 0pmod p,(1le ile p-1)
]
由
[{pchoose i}={p!over i!(p-i)!}={pover i} {(p-1)!over(i-1)!(p-1-i+1)!} {pover i} {(p-1)!over(i-1)!(p-i)!}={pover i}{p-1choose i-1}
]
得证。
然后根据这种性质和二项式定理,我们马上得出
[(1+x)^pequiv {pchoose0}1^p+{pchoose1}x^{2}+....+{pchoose p}x^pequiv {pchoose0}1^px^0+{pchoose p}1^0x^pequiv 1+x^ppmod p
]
然后我们接下来要求证
[{achoose b}equiv {a_0choose b_0}{a_1pchoose b_1p}{a_2p^2choose b_2p^2}dotspmod p
]
令(a=lp+r,b=sp+j)
求证({achoose b}equiv {lchoose s}{rchoose j}pmod p)然后利用性质递归求解就可以了。
继续从二次项定理出发
[(1+x)^a=(1+x)^{lp} cdot (1+x)^r
]
然后展开((1+x)^{lp})
[(1+x)^{lp} equiv ((1+x)^p)^l equiv (1+x^p)^lpmod p
]
[ herefore (1+x)^a equiv (1+x^p)^l(1+x)^rpmod p
]
观察项(x^b)的系数
[ecause {a^bchoose x^b}equiv{lchoose s}x^{sp}{rchoose j}x^jpmod p
]
[ herefore {achoose b}x^b equiv {lchoose s}{rchoose j}x^bpmod p
]
[ herefore {achoose b}equiv {lchoose s}{rchoose j} equiv {lfloor {aover p}
floorchoose lfloor {bover p}
floor}{amod pchoose bmod p}pmod p
]
得证
实现
#include <cstdio>
#define ll long long
#define re register
#define il inline
#define gc getchar
#define pc putchar
template <class T>
void read(T &x) {
re bool f = 0;
re char c = gc();
while ((c < '0' || c > '9') && c != '-') c = gc();
if (c == '-') f = 1, c = gc();
x = 0;
while (c >= '0' && c <= '9') x = x * 10 + (c ^ 48), c = gc();
f && (x = -x);
}
template <class T>
void print(T x) {
if (x < 0) pc('-'), x = -x;
if (x >= 10) print(x / 10);
pc((x % 10) ^ 48);
}
template <class T>
void prisp(T x) {
print(x);
pc(' ');
}
template <class T>
void priln(T x) {
print(x);
pc('
');
}
ll fac[100005];
ll pow(ll b, int t, ll p) {
ll r;
for (r = 1; t; t >>= 1, b = (b * b) % p)
if (t & 1) r = (r * b) % p;
return r;
}
ll C(ll n, ll m, ll p) {
if (m > n) return 0;
return (fac[n] * pow(fac[m], p - 2, p) % p) * pow(fac[n - m], p - 2, p) % p;
}
ll lucas(ll n, ll m, ll p) {
if (m == 0) return 1;
return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}
int main() {
int t;
read(t);
while (t--) {
ll n, m, p;
read(n);
read(m);
read(p);
fac[0] = 1;
for (int i = 1; i <= p; ++i) fac[i] = (fac[i - 1] * i) % p;
priln(lucas(n + m, m, p));
}
}