洛谷 P5520 [yLOI2019] 青原樱(组合数学 + 不互质逆元)

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} Cnm+1m。另一种思路更简单,就是先抽出m – 1个位置出来,然后剩下的位置里选m个,直接就是 C n – m + 1 m C_{n – m + 1}^{m} Cnm+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(ap) mod c即为答案,目前还不知道原理以后再看看吧。s://.luogu.com.cn/discuss/show/143253。

#include
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;
}

你可能感兴趣的:(组合数学,数论)