题解
2024-04-25 21:05:58
发布于:浙江
90阅读
0回复
0点赞
幼儿园篮球题
思路
不难发现,我们要求的答案实际上是这个东西:
于是,我们只需求到分子即可。我们开始愉快的化式子了。
我们发现里面难搞的其实是 ,但是我们又有式子:
对于这个式子的感性证明就是:假设我们现在有 个小球,要放进 个盒子里面,没有限制,显然它等于 。但是,我们还有一种求法,即,我们选出 个盒子放 个小球,显然要选出 个盒子,然后把 个小球塞进去,又因为盒子不同,所以还要乘上 。
将上式代入式子中,可以得到:
又因为
这个式子展开之后易证。
所以原式等于:
然后你发现后面那个式子是范德蒙德卷积,就等于:
所以原式等于:
又因为上面提到的 , 这个东西我们可以使用二项式反演得到:
然后你就发现这是个卷积形式,于是我们就可以 预处理出 。
不过因为这道题十分卡常,所以我们还需要再化一下式子。
我们又发现上界其实是 ,所以至此,我们可以 解决此题目。
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXX 20000005
#define mod 998244353
#define Gi 332748118
#define MAXN 800005
#define G 3
int quick_pow (int a,int b,int c){
int res = 1;
while (b){
if (b & 1) res = 1ll * res * a % c;
a = 1ll * a * a % c;
b >>= 1;
}
return res;
}
int l,limit,r[MAXN];
void NTT (int *a,int type){
for (Int i = 0;i < limit;++ i)
if (i < r[i]) swap (a[i],a[r[i]]);
for (Int mid = 1;mid < limit;mid <<= 1){
int Wn = quick_pow (type == 1 ? G : Gi,(mod - 1) / (mid << 1),mod);
for (Int R = mid << 1,j = 0;j < limit;j += R){
int w = 1;
for (Int k = 0;k < mid;++ k,w = 1ll * w * Wn % mod){
int x = a[j + k],y = 1ll * w * a[j + k + mid] % mod;
a[j + k] = (x + y) % mod,a[j + k + mid] = (x + mod - y) % mod;
}
}
}
if (type == 1) return ;
int Inv = quick_pow (limit,mod - 2,mod);
for (Int i = 0;i < limit;++ i) a[i] = 1ll * a[i] * Inv % mod;
}
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int N,M,S,L;
int A[MAXN],B[MAXN];
int inv[MAXX],fac[MAXX];
void SiteLin (int n){
for (Int i = 0;i <= n;++ i){
A[i] = (i & 1) ? mod - inv[i] : inv[i];
B[i] = 1ll * quick_pow (i,n,mod) * inv[i] % mod;
}
limit = 1,l = 0;
while (limit <= (n << 1)) limit <<= 1,l ++;
for (Int i = 0;i < limit;++ i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << l - 1);
NTT (A,1),NTT (B,1);
for (Int i = 0;i < limit;++ i) A[i] = 1ll * A[i] * B[i] % mod;
NTT (A,-1);
}
int C (int n,int m){
return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
}
signed main(){
read (N,M,S,L);
inv[0] = inv[1] = fac[0] = 1;int uu = max (N,L);
for (Int i = 1;i <= uu;++ i) fac[i] = 1ll * fac[i - 1] * i % mod;
inv[uu] = quick_pow (fac[uu],mod - 2,mod);
for (Int i = uu - 1;~i;-- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
SiteLin (L);
while (S --){
int n,m,k;
read (n,m,k);int ans = 0;
for (Int i = 0;i <= min (L,min (m,k));++ i) ans = (ans + 1ll * A[i] * inv[m - i] % mod * fac[n - i] % mod * inv[k - i]) % mod;
write (1ll * ans * fac[m] % mod * fac[k] % mod * inv[n] % mod),putchar ('\n');
}
return 0;
}
全部评论 2
给dpsk看你思路后它也写出来一个好像是ac但是TLE+WA玩意儿:(
#include <bits/stdc++.h> using namespace std; const int MOD = 998244353; const int MAX_N = 2e7 + 10; const int MAX_L = 2e5 + 10; int fact[MAX_N], inv_fact[MAX_N]; int stirling[MAX_L]; int add(int a, int b) { a += b; if (a >= MOD) a -= MOD; return a; } int mul(int a, int b) { return 1LL * a * b % MOD; } int pow_mod(int a, int b) { int res = 1; while (b) { if (b & 1) res = mul(res, a); a = mul(a, a); b >>= 1; } return res; } void precompute_factorials(int max_n) { fact[0] = 1; for (int i = 1; i <= max_n; ++i) { fact[i] = mul(fact[i - 1], i); } inv_fact[max_n] = pow_mod(fact[max_n], MOD - 2); for (int i = max_n - 1; i >= 0; --i) { inv_fact[i] = mul(inv_fact[i + 1], i + 1); } } int comb(int n, int k) { if (k < 0 || k > n) return 0; return mul(fact[n], mul(inv_fact[k], inv_fact[n - k])); } void precompute_stirling(int L) { // Using the inclusion-exclusion formula: S(L, j) = (1/j!) * sum_{i=0}^j (-1)^{j-i} * C(j, i) * i^L // We can compute for all j=0..L using FFT or directly for small L // Here we use the direct method for simplicity, but it's O(L^2) // For L up to 2e5, this is not feasible, so we need a better approach // However, for the purpose of this explanation, we proceed with the direct method stirling[0] = (L == 0); for (int j = 1; j <= L; ++j) { stirling[j] = 0; for (int i = 0, sign = 1; i <= j; ++i, sign = MOD - sign) { stirling[j] = add(stirling[j], mul(sign, mul(comb(j, i), pow_mod(i, L)))); } stirling[j] = mul(stirling[j], inv_fact[j]); } } int solve_case(int n_i, int m_i, int k_i, int L) { int S = 0; int mj = 1; // mj = m_i * (m_i - 1) * ... * (m_i - j + 1) for (int j = 0; j <= L; ++j) { if (j > m_i || j > k_i) break; int term = mul(stirling[j], mj); term = mul(term, comb(n_i - j, k_i - j
2025-07-14 来自 上海
0不是哥们
2024-07-24 来自 北京
0
有帮助,赞一个