s://.luogu.com.cn/problem/P5520
我组合数学也太菜了吧,这题思路相当简单。第一种想法是:m个树占m个位置,然后拿m – 1个位置填在m个树之间,然后就是一个n – 2 * m + 1个球放m + 1个盒子里,盒子可以为空的放法数了,结果就是
C
n
–
m
+
1
m
C_{n – m + 1}^{m}
Cn–m+1m。另一种思路更简单,就是先抽出m – 1个位置出来,然后剩下的位置里选m个,直接就是
C
n
–
m
+
1
m
C_{n – m + 1}^{m}
Cn–m+1m种了,然后把这m – 1个位置插在两两之间可以保证一定没有相邻的,太强了。
然后还有个问题就是这题的p不一定是质数也不一定互质,然后我看到了一种求(a/b)%c的方法:(其中b|a),先求k=gcd(b,c),然后求b/k的逆元p,接着计算
(
a
∗
p
)
m
o
d
c
k
\frac{(a*p)\ mod\ c}{k}
k(a∗p) mod c即为答案,目前还不知道原理以后再看看吧。s://.luogu.com.cn/discuss/show/143253。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;
ll fac[maxn], mod;
ll gcd(ll a, ll b){return b == 0 ? a : gcd(b, a % b);}
ll x, y;
void extgcd(ll a, ll b, ll &x, ll &y)
{
if (b == 0) x = 1, y = 0;
else{
extgcd(b, a % b, y, x);
y -= (a / b) * x;
}
}
ll C(int n, int m)
{
ll k = gcd(fac[m] * fac[n - m], mod);
extgcd(fac[m] * fac[n - m] / k, mod / k, x, y);
if (x < 0) x += mod / k;
return fac[n] * x % mod / k;
}
int main()
{
int t, n, m;
cin >> t >> n >> m >> mod;
fac[0] = fac[1] = 1;
for (int i = 2; i < maxn; ++i) fac[i] = (i * fac[i - 1]) % mod;
cout << C(n - m + 1, m) * fac[m] % mod << endl;
return 0;
}