LOJ#3119 随机立方体

解:极大值至少为1。我们尝试把最大那个数的影响去掉。

最大那个数所在的一层(指一个三维十字架)都是不可能成为最大值的。

考虑容斥。我们试图求除了最大值以外至少有k个极大值的概率。

我们钦定某k个位置是极大值,且钦定顺序。这样的方案数有ni↓mi↓Li↓种。

考虑每种方案的概率。从小到大考虑,对于最小的那个极大值,如果是极大值,就要大于一个三维十字架中的所有数,这样的概率是1 / 集合大小。

对于次小极大值,它要大于自己的三维十字架和最小值的三维十字架的并。概率还是1 / 集合大小。

于是依次考虑完每个极大值,把概率求积即可。容斥的时候记得乘组合数。

 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代码

这题非常卡常...

 

posted @ 2019-05-30 18:25  huyufeifei  阅读(150)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜