1. 程式人生 > 其它 >luogu P2791 幼兒園籃球題

luogu P2791 幼兒園籃球題

https://www.luogu.com.cn/problem/P2791

讚美出題人(bushi

如果做過luogu P6031 CF1278F Cards 加強版
這題,按照套路推一推就可以推出來了
注意其中有一步要用範德蒙德卷積

code:

#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
#define M 20000050
#define N 800050
using namespace std;
inline int rd() {
    int x = 0; char ch = getchar();
    for(; ch < '0' || ch > '9' ;) ch = getchar();
    for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x << 1) + (ch - '0'), ch = getchar();
    return x;
}
int add(int x, int y) { x += y;
    if(x >= mod) x -= mod;
    return x;
}
int sub(int x, int y) { x -= y;
    if(x < 0) x += mod;
    return x;
}
int mul(int x, int y) {
    return 1ll * x * y % mod;
}
int qpow(int x, int y) {
    int ret = 1;
    for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
    return ret;
}
const int G = 3;
const int Ginv = qpow(3, mod - 2);
int rev[N];
void ntt(int *a, int n, int o) {
    for(int i = 1; i < n; i ++) if(i > rev[i]) swap(a[i], a[rev[i]]);
    for(int len = 2; len <= n; len <<= 1) {
        int w0 = qpow((o == 1)? G : Ginv, (mod - 1) / len);
        for(int j = 0; j < n; j += len) {
            int wn = 1;
            for(int k = j; k < j + (len >> 1); k ++, wn = mul(wn, w0)) {
                int X = a[k], Y = mul(wn, a[k + (len >> 1)]);
                a[k] = add(X, Y), a[k + (len >> 1)] = sub(X, Y);
            }
        }
    }
    int ninv = qpow(n, mod - 2);
    if(o == -1) for(int i = 0; i < n; i ++) a[i] = mul(a[i], ninv);
}
int fac[M], ifac[M], a[N], b[N], S[N];
void init(int n) {
    fac[0] = 1;
    for(int i = 1; i <= n; i ++) fac[i] = mul(fac[i - 1], i);
    ifac[n] = qpow(fac[n], mod - 2);
    for(int i = n - 1; i >= 0; i --) ifac[i] = mul(ifac[i + 1], (i + 1));
}
int C(int n, int m) {
    return mul(fac[n], mul(ifac[m], ifac[n - m]));
}
int vis[N], prime[N], sz;
int idk[N];
void get(int n) {
    idk[1] = 1;
    for(int i = 2; i <= n; i ++) {
        if(!vis[i]) {
            idk[i] = qpow(i, n);
            prime[++ sz] = i;
        }
        for(int j = 1; j <= sz && i * prime[j] <= n; j ++) {
            vis[prime[j] * i] = 1; idk[prime[j] * i] = 1ll * idk[prime[j]] * idk[i] % mod;
            if(i % prime[j] == 0) break;
        }
    }
}
void pre(int n) {
    get(n);
    for(int i = 0; i <= n; i ++) a[i] = mul((i & 1)? (mod - 1) : 1, ifac[i]);
    for(int i = 0; i <= n; i ++) b[i] = mul(idk[i], ifac[i]);
    int len = 1;
    for(; len <= n + n; len <<= 1);
    for(int i = 1; i < len; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (len >> 1));
    ntt(a, len, 1), ntt(b, len, 1);
    for(int i = 0; i < len; i ++) a[i] = mul(a[i], b[i]);
    ntt(a, len, -1);
    for(int i = 0; i <= n; i ++) S[i] = a[i];
}
int n, m, s, l, k;
int main() {
    n = rd(), m = rd(), s = rd(), l = rd();
    init(max(n, l)), pre(l);
    while(s --) {
        n = rd(), m = rd(), k = rd();
        int ans = 0;
        for(int j = 0; j <= min(k, min(m, l)); j ++) 
        ans = add(ans, 1ll * S[j] * ifac[m - j] % mod * ifac[k - j] % mod * fac[n - j] % mod);
        //ans = add(ans, mul(fac[j], mul(S[j], mul(C(m, j), C(n - j, k - j)))));
        printf("%lld\n", 1ll * ans * fac[m] % mod * fac[k] % mod * ifac[n] % mod);
    }
    return 0;
}