BZOJ 2142: 礼物

m 个人收到礼物的数量分别为 w i ,则答案为

( n w 1 ) ( n w 1 w 2 ) ( n w 1 w m 1 w m )

用扩展 L u c a s 定理即可。

注意多次调用 e x c r t 时,不能直接用 c [ 1 ] m [ 1 ] 存答案了。

#include <cstdio>
#include <cmath>

typedef long long LL;
const int N = 100005;
int n, m, p, v[6], w[6], mi[N], mo[N], c[N], cnt;
LL x, y;

int pow(int a, int b, int p) {
    int res = 1;
    for (; b; b >>= 1, a = 1LL * a * a % p)
        if (b & 1) res = 1LL * res * a % p;
    return res;
}
LL mul(LL a, LL b, LL p) {
    int res = 0, f = 1;
    if (a < 0) a = -a, f = -f;
    if (b < 0) b = -b, f = -f;
    for (; b; b >>= 1, a = (a + a) % p)
        if (b & 1) res = (res + a) % p;
    return res * f;
}
int exgcd(int a, int b, LL &x, LL &y) {
    if (b == 0) { x = 1, y = 0; return a; }
    int t = exgcd(b, a % b, y, x); y -= a / b * x; return t;
}
int inv(int a, int p) {
    int t = exgcd(a, p, x, y);
    return (x % p + p) % p;
}
int fac(int n, int pi, int pk) {
    if (n == 0) return 1;
    int res = 1;
    for (int i = 2; i <= pk; ++i)
        if (i % pi) res = 1LL * res * i % pk;
    res = pow(res, n / pk, pk);
    for (int i = 2; i <= n % pk; ++i)
        if (i % pi) res = 1LL * res * i % pk;
    return 1LL * res * fac(n / pi, pi, pk) % pk;
}
int calc(int n, int m, int pi, int pk) {
    int up = fac(n, pi, pk), d1 = fac(m, pi, pk), d2 = fac(n - m, pi, pk);
    int k = 0;
    for (int i = n; i; i /= pi) k += i / pi;
    for (int i = m; i; i /= pi) k -= i / pi;
    for (int i = n - m; i; i /= pi) k -= i / pi;
    return 1LL * pow(pi, k, pk) * up % pk * inv(d1, pk) % pk * inv(d2, pk) % pk;
}
LL excrt() {
    LL t, mod, M = mo[1], C = c[1];
    for (int i = 2; i <= cnt; ++i) {
        t = exgcd(M, mo[i], x, y);
        mod = M / t * mo[i];
        x = mul(x, (c[i] - C) / t, mod);
        C = (C + mul(x, M, mod)) % mod, M = mod;
    }
    return (C + M) % M;
}
int exlucas() {
    int res = 1, lim = sqrt(p), x = p, pk;
    for (int i = 2; i <= lim; ++i) {
        if (x % i == 0) {
            pk = 1;
            while (x % i == 0) x /= i, pk *= i;
            mo[++cnt] = pk, mi[cnt] = i;
        }
    }
    if (x > 1) mo[++cnt] = mi[cnt] = x;
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= cnt; ++j)
            c[j] = calc(v[i], w[i], mi[j], mo[j]);
        res = 1LL * res * excrt() % p;
    }
    return res;
}

int main() {
    scanf("%d%d%d", &p, &n, &m);
    v[0] = n;
    for (int i = 1; i <= m; ++i) {
        scanf("%d", &w[i]);
        v[i] = v[i-1] - w[i-1];
        if (v[i] < w[i]) { puts("Impossible"); return 0; }
    }
    printf("%d\n", exlucas());
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Milkyyyyy/article/details/82150506