LOJ#3119 隨機立方體

解:極大值至少爲1。咱們嘗試把最大那個數的影響去掉。c++

最大那個數所在的一層(指一個三維十字架)都是不可能成爲最大值的。ide

考慮容斥。咱們試圖求除了最大值之外至少有k個極大值的機率。spa

咱們欽定某k個位置是極大值,且欽定順序。這樣的方案數有ni↓mi↓Li↓種。code

考慮每種方案的機率。從小到大考慮,對於最小的那個極大值,若是是極大值,就要大於一個三維十字架中的全部數,這樣的機率是1 / 集合大小。blog

對於次小極大值,它要大於本身的三維十字架和最小值的三維十字架的並。機率仍是1 / 集合大小。it

因而依次考慮完每一個極大值,把機率求積便可。容斥的時候記得乘組合數。event

 1 #include <bits/stdc++.h>
 2 
 3 typedef long long LL;
 4 
 5 const int MO = 998244353, N = 5000010;
 6 
 7 int n, m, K, L;
 8 int fac[N], inv[N], invn[N];
 9 
10 inline int qpow(int a, int b) {
11     int ans = 1;
12     while(b) {
13         if(b & 1) ans = 1ll * ans * a % MO;
14         a = 1ll * a * a % MO;
15         b = b >> 1;
16     }
17     return ans;
18 }
19 inline int Inv(int x) {
20     if(x < N) return inv[x];
21     return qpow(x, MO - 2);
22 }
23 inline int C(int n, int m) {
24     return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO;
25 }
26 inline int Down(int n, int k) {
27     return 1ll * fac[n] * invn[n - k] % MO;
28 }
29 inline int iDown(int n, int k) {
30     return 1ll * invn[n] * fac[n - k] % MO;
31 }
32 inline int dec(int x) {
33     return 1ll * (n - x) * (m - x) % MO * (L - x) % MO;
34 }
35 
36 inline void solve() {
37     
38     scanf("%d%d%d%d", &n, &m, &L, &K);
39     int ans = 0, lm = std::min(std::min(n, m), L);
40     int V = 1ll * n * m % MO * L % MO;
41     for(int i = K - 1; i <= lm; i++) {
42         int p = 1;
43         for(int j = 1; j <= i; j++) {
44             p = 1ll * p * (n - i + j - 1) % MO * (m - i + j - 1) % MO * (L - i + j - 1) % MO;
45             p = 1ll * Inv((V - dec(j) + MO) % MO) * p % MO;
46         }
47         p = 1ll * p * C(i, K - 1) % MO;
48         if((K - i) & 1) {
49             ans = (ans + p) % MO;
50         }
51         else {
52             ans = (ans - p) % MO;
53         }
54     }
55     printf("%d\n", (ans + MO) % MO);
56     return;
57 }
58 
59 int main() {
60 
61     fac[0] = inv[0] = invn[0] = 1;
62     fac[1] = inv[1] = invn[1] = 1;
63     for(int i = 2; i < N; i++) {
64         fac[i] = 1ll * i * fac[i - 1] % MO;
65         inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
66         invn[i] = 1ll * inv[i] * invn[i - 1] % MO;
67     }
68     
69     //printf(" = %lld \n", 142606337ll * fac[8] % MO);
70     
71     int T;
72     scanf("%d", &T);
73     while(T--) {
74         solve();
75     }
76     
77     return 0;
78 }
50分代碼,幫助理解
 1 #include <bits/stdc++.h>
 2 
 3 #pragma GCC optimize("Ofast") 
 4 
 5 typedef long long LL;
 6 
 7 const int MO = 998244353, N = 5000010;
 8 
 9 int n, m, K, L;
10 int fac[N], inv[N], invn[N], val[N], ival[N], D[N];
11 
12 inline int qpow(int a, int b) {
13     int ans = 1;
14     while(b) {
15         if(b & 1) ans = 1ll * ans * a % MO;
16         a = 1ll * a * a % MO;
17         b = b >> 1;
18     }
19     return ans;
20 }
21 inline int Inv(int x) {
22     if(x < N && x >= 0) return inv[x];
23     return qpow(x, MO - 2);
24 }
25 inline int C(int n, int m) {
26     if(n < 0 || m < 0 || n < m) return 0;
27     return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO;
28 }
29 inline int Down(int n, int k) {
30     return 1ll * fac[n] * invn[n - k] % MO;
31 }
32 inline int iDown(int n, int k) {
33     return 1ll * invn[n] * fac[n - k] % MO;
34 }
35 inline int dec(int x) {
36     return 1ll * (n - x) * (m - x) % MO * (L - x) % MO;
37 }
38 
39 inline void solve() {
40     
41     scanf("%d%d%d%d", &n, &m, &L, &K);
42     K--;
43     int ans(0), lm(std::min(std::min(n, m), L));
44     int V = 1ll * n * m % MO * L % MO;
45     
46     val[0] = 1;
47     D[0] = V;
48     for(register int i(1); i <= lm; ++i) {
49         D[i] = (dec(i));
50         val[i] = 1ll * val[i - 1] * (V - D[i]) % MO;
51     }
52     ival[lm] = qpow(val[lm], MO - 2);
53     for(register int i(lm - 1); i >= K; --i) {
54         ival[i] = 1ll * ival[i + 1] * (V - D[i + 1]) % MO;
55     }
56     int t = 1ll * Down(n - 1, K - 1) * Down(m - 1, K - 1) % MO * Down(L - 1, K - 1) % MO;
57     for(register int i(K); i <= lm; ++i) {
58         //t = 1ll * t * (n - i) % MO * (m - i) % MO * (L - i) % MO * inv[i - K] % MO;
59         t = 1ll * t * D[i] % MO * inv[i - K] % MO;
60         int p = 1ll * t * ival[i] % MO * fac[i] % MO;
61         ((K + i) & 1) ? ans -= p : ans += p;
62         if(ans >= MO) ans -= MO;
63         if(ans < 0) ans += MO;
64     }
65     ans = 1ll * ans * invn[K] % MO;
66     printf("%d\n", ans < 0 ? ans + MO : ans);
67     return;
68 }
69 
70 /*
71 1
72 1000 1000 1000 10
73 */
74 
75 int main() {
76 
77     fac[0] = inv[0] = invn[0] = 1;
78     fac[1] = inv[1] = invn[1] = 1;
79     for(register int i(2); i < N; ++i) {
80         fac[i] = 1ll * i * fac[i - 1] % MO;
81         inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
82         invn[i] = 1ll * inv[i] * invn[i - 1] % MO;
83     }
84     
85     //printf(" = %lld \n", 142606337ll * fac[8] % MO);
86     
87     int T;
88     scanf("%d", &T);
89     while(T--) {
90         solve();
91     }
92     
93     return 0;
94 }
AC代碼

這題很是卡常...ast

相關文章
相關標籤/搜索