Description有 n n n 个管道,每个管道的最大大小为 a a a ,每次等概率随机选一个没满的管道里放一个石子,当所有管道的大小都 ≥ b \geq b ≥ b 时停止,问装满的管道的期望个数,与 998244353 998244353 9 9 8 2 4 4 3 5 3 取模。
1 ≤ n ≤ 250 , 1 ≤ b < a ≤ 250 1 \le n \le 250,1 \le b < a \le 250 1 ≤ n ≤ 2 5 0 , 1 ≤ b < a ≤ 2 5 0 。
Solution先考虑一个引理:有 n n n 个集合,有一些集合不能加数,那么对于所有能加数的集合,它是下一个被加数的集合的概率刚好等于所有集合都能加数,且它是原本所有能加数的集合中第一个加数的概率。这个很好证。
所以原题就可以转化为每次随便加石子,最终所有的管道的大小都 ≥ b \geq b ≥ b 时大小 ≥ a \geq a ≥ a 的期望个数。
不妨先求 1 1 1 号管道被装满的概率,最终答案就是这个概率× n \times n × n 。
由于操作序列是无法确定长度的,所以不好求概率。考虑利用引理,定义一个管道不能再加石子当且仅当它是 1 1 1 号且 ≥ a \geq a ≥ a 或者不是 1 1 1 号且 ≥ b \geq b ≥ b 。
这样的话操作序列长就是 ( n − 1 ) × b + a (n-1)\times b+a ( n − 1 ) × b + a 了,然后只要用 1 1 1 减去最后一步是 1 1 1 号管道的概率。
不妨设 t i t_i t i 表示 i i i 最后一次操作的时间(1 ≤ t 1 < t 2 < ⋯ < t n − 1 < ( n − 1 ) × b + a 1\leq t_1<t_2<\dots<t_{n-1}<(n-1)\times b+a 1 ≤ t 1 < t 2 < ⋯ < t n − 1 < ( n − 1 ) × b + a ),则最后一步是 1 1 1 的概率即为:
∏ i = 1 n − 1 ( t i − 1 − ( i − 1 ) b b − 1 ) ∏ i = 1 n − 1 ( n − i + 1 ) t i − t i − 1 \frac{\prod_{i=1}^{n-1}{\binom{t_i-1-(i-1)b}{b-1}}}{\prod_{i=1}^{n-1}{(n-i+1)^{t_{i}-t_{i-1}}}} ∏ i = 1 n − 1 ( n − i + 1 ) t i − t i − 1 ∏ i = 1 n − 1 ( b − 1 t i − 1 − ( i − 1 ) b )
上面那个是总的方案数,下面是选择每个位置要乘的概率。
然后对这个进行 dp 即可,设 f i , j f_{i,j} f i , j 表示当前在时间 i i i ,有 j j j 个非 1 1 1 管道被填满的概率,则 f i + 1 , j ← f i , j n − j , f i + 1 , j + 1 ← f i , j × ( i − j ⋅ b b − 1 ) n − j f_{i+1,j}\leftarrow \frac{f_{i,j}}{n-j},f_{i+1,j+1}\leftarrow \frac{f_{i,j}\times \binom{i-j\cdot b}{b-1}}{n-j} f i + 1 , j ← n − j f i , j , f i + 1 , j + 1 ← n − j f i , j × ( b − 1 i − j ⋅ b ) 。
最终答案就是 n × ( 1 − ( n − 1 ) ! × f ( n − 1 ) b + a − 1 , n − 1 ) n\times \left(1-(n-1)!\times f_{(n-1)b+a-1,n-1}\right) n × ( 1 − ( n − 1 ) ! × f ( n − 1 ) b + a − 1 , n − 1 ) 。
时间复杂度:O ( n 2 b + n a ) O(n^2b+na) O ( n 2 b + n a ) 。
Code1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <bits/stdc++.h> const int kMaxN = 255 , kMaxS = 9e4 + 5 , kMod = 998244353 ;int n, a, b;int fac[kMaxS], ifac[kMaxS], inv[kMaxS], f[kMaxS][kMaxN];constexpr int qpow (int bs, int64_t idx = kMod - 2 ) { int ret = 1 ; for (; idx; idx >>= 1 , bs = (int64_t )bs * bs % kMod) if (idx & 1 ) ret = (int64_t )ret * bs % kMod; return ret; }inline int add (int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }inline int sub (int x, int y) { return (x >= y ? x - y : x - y + kMod); }inline void inc (int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }inline void dec (int &x, int y) { (x -= y) < 0 ? x += kMod : x; }int C (int m, int n) { if (m < n || m < 0 || n < 0 ) return 0 ; return 1ll * fac[m] * ifac[n] % kMod * ifac[m - n] % kMod; }void prework () { fac[0 ] = ifac[0 ] = fac[1 ] = ifac[1 ] = inv[1 ] = 1 ; for (int i = 2 ; i <= n * a; ++i) { inv[i] = 1ll * (kMod - kMod / i) * inv[kMod % i] % kMod; fac[i] = 1ll * i * fac[i - 1 ] % kMod; ifac[i] = 1ll * inv[i] * ifac[i - 1 ] % kMod; } }void dickdreamer () { std::cin >> n >> a >> b; prework (); int m = (n - 1 ) * b + a; f[0 ][0 ] = 1 ; for (int i = 0 ; i < m; ++i) { for (int j = 0 ; j <= std::min (n - 1 , i / b); ++j) { int p = 1ll * f[i][j] * inv[n - j] % kMod; inc (f[i + 1 ][j], p), inc (f[i + 1 ][j + 1 ], 1ll * p * C (i - j * b, b - 1 ) % kMod); } } std::cout << 1ll * n * sub (1 , 1ll * f[m - 1 ][n - 1 ] * fac[n - 1 ] % kMod) % kMod << '\n' ; }int32_t main () {#ifdef ORZXKR freopen ("in.txt" , "r" , stdin); freopen ("out.txt" , "w" , stdout);#endif std::ios::sync_with_stdio (0 ), std::cin.tie (0 ), std::cout.tie (0 ); int T = 1 ; while (T--) dickdreamer (); return 0 ; }