题意:有一个1001 * n的矩形,每个位置有q的概率为1。求紧贴下边界的最大的全1子矩形面积恰为k的概率。n <= 1e9,k <= 1000。

解:只需考虑每一列最下面一个0的位置。

首先有个n = 1的部分分,答案显然就是qk(1-q)。

中间还有些部分分,什么打表啊笛卡尔树上DP啊...感觉有毒。

接下来就是一个nk的DP,直接获得70分...感觉有毒。

首先发现这个恰好为k不好处理,就考虑计算<= k和<= k - 1,然后相减。注意因为面积全是整数而我们不是求期望,所以不会有非整数的出现。

考虑到下边界一定被若干个0分隔开,且每两个相邻0之间距离不大于k。于是我们按照0来DP。设fi表示1001 * i的矩形符合条件的概率。那么每次枚举这一段下边界的最后一个0在j位置,那么概率就是fj-1 * (1 - q) * (长为i-j的一段最下面全是1,符合条件的概率)。

考虑怎么求最后那个东西。

发现把最下面一行去掉之后好像有点像一个子问题?然而好像不行...实际上是一种类似最值分治的做法。

考虑这些列中最低的一列在哪(枚举得到),然后左右两边就是一个真实子问题,而中间这一列就是n = 1的部分分。但是还是不知道最低一列到底有多低...发现k只有1000,所以就可以枚举?

然而正解是多加一维状态表示高度。设gi,j表示1001 * i的矩形,最下面j * i的矩形全是1,且满足条件的概率。设j + 1行第一个0在p位置,那么gi,j += gp-1,j+1 * gi-p,j * qj * (1-q)。

边界条件就是g0,x = 1。

这东西难调死了......注意fn其实等于gn,0

 1 /**
 2  * There is no end though there is a start in space. ---Infinity.
 3  * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
 4  * Only the person who was wisdom can read the most foolish one from the history.
 5  * The fish that lives in the sea doesn't know the world in the land.
 6  * It also ruins and goes if they have wisdom.
 7  * It is funnier that man exceeds the speed of light than fish start living in the land.
 8  * It can be said that this is an final ultimatum from the god to the people who can fight.
 9  *
10  * Steins;Gate
11  */
12 
13 #include <bits/stdc++.h>
14 
15 typedef long long LL;
16 const int N = 1010, MO = 998244353;
17 
18 int n, K, q, g[N][N], f[N], pw[N];
19 
20 inline int qpow(int a, int b) {
21     int ans = 1;
22     while(b) {
23         if(b & 1) ans = 1ll * ans * a % MO;
24         a = 1ll * a * a % MO;
25         b = b >> 1;
26     }
27     return ans;
28 }
29 
30 inline int cal(int k) {
31     if(k < 0) return 0;
32     if(k == 0) return qpow(1 - q + MO, n);
33     memset(f, 0, sizeof(f));
34     memset(g, 0, sizeof(g));
35 
36     for(int i = 0; i <= k + 1; i++) {
37         g[0][i] = 1;
38     }
39 
40     for(int i = 1; i <= k; i++) {
41         for(int j = k / i; j >= 0; j--) {
42             /// g[i][j]
43             g[i][j] = g[i][j + 1];
44             for(int p = 1; p <= i; p++) {
45                 (g[i][j] += 1ll * g[p - 1][j + 1] * g[i - p][j] % MO * pw[j] % MO * (1 - q + MO) % MO) %= MO;
46             }
47             //printf("g %d %d = %d \n", i, j, g[i][j]);
48         }
49     }
50 
51     //puts("");
52 
53     /// cal f
54     f[0] = 1;
55     for(int i = 1; i <= n; i++) {
56         /// f[i]
57         if(i <= k) f[i] = g[i][1];
58         for(int j = std::max(1, i - k); j <= i; j++) {
59             (f[i] += 1ll * f[j - 1] * (1 - q + MO) % MO * g[i - j][1] % MO) %= MO;
60         }
61         //printf("f %d = %d \n", i, f[i]);
62     }
63 
64     //printf("\n\n");
65 
66     return f[n];
67 }
68 
69 /*
70 2 2 1 2
71 */
72 
73 int main() {
74     int x, y;
75     scanf("%d%d%d%d", &n, &K, &x, &y);
76     q = 1ll * x * qpow(y, MO - 2) % MO;
77     //printf("q = %d \n", q);
78     pw[0] = 1;
79     for(int i = 1; i <= K; i++) {
80         pw[i] = 1ll * pw[i - 1] * q % MO;
81     }
82 
83     if(n == 1) {
84         int ans = 1ll * qpow(q, K) * (1 - q + MO) % MO;
85         printf("%d\n", ans);
86         return 0;
87     }
88 
89     int ans = (cal(K) - cal(K - 1) + MO) % MO;
90     printf("%d\n", ans);
91 
92     return 0;
93 }
70分代码

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-06-17
  • 2022-12-23
  • 2022-12-23
  • 2022-01-30
  • 2021-09-19
  • 2022-12-23
猜你喜欢
  • 2021-06-18
  • 2022-02-27
  • 2021-07-25
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-08-09
相关资源
相似解决方案