LOJ#2304 泳池

題意:有一個1001 * n的矩形,每一個位置有q的機率爲1。求緊貼下邊界的最大的全1子矩形面積恰爲k的機率。n <= 1e9,k <= 1000。c++

解:只需考慮每一列最下面一個0的位置。dom

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

中間還有些部分分,什麼打表啊笛卡爾樹上DP啊...感受有毒。優化

接下來就是一個nk的DP,直接得到70分...感受有毒。ui

首先發現這個剛好爲k很差處理,就考慮計算<= k和<= k - 1,而後相減。注意由於面積全是整數而咱們不是求指望,因此不會有非整數的出現。this

考慮到下邊界必定被若干個0分隔開,且每兩個相鄰0之間距離不大於k。因而咱們按照0來DP。設fi表示1001 * i的矩形符合條件的機率。那麼每次枚舉這一段下邊界的最後一個0在j位置,那麼機率就是fj-1 * (1 - q) * (長爲i-j的一段最下面全是1,符合條件的機率)。spa

考慮怎麼求最後那個東西。code

發現把最下面一行去掉以後好像有點像一個子問題?然而好像不行...其實是一種相似最值分治的作法。blog

考慮這些列中最低的一列在哪(枚舉獲得),而後左右兩邊就是一個真實子問題,而中間這一列就是n = 1的部分分。可是仍是不知道最低一列到底有多低...發現k只有1000,因此就能夠枚舉?it

然而正解是多加一維狀態表示高度。設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分代碼

因而咱們來個矩陣快速冪優化,得到了90分的好成績!

  1 #include <bits/stdc++.h>
  2 
  3 typedef long long LL;
  4 const int N = 1010, MO = 998244353;
  5 
  6 int n, K, q, g[N][N], f[N], pw[N];
  7 int A[110][110], ANS[110][110], C[110][110];
  8 
  9 inline int qpow(int a, int b) {
 10     int ans = 1;
 11     while(b) {
 12         if(b & 1) ans = 1ll * ans * a % MO;
 13         a = 1ll * a * a % MO;
 14         b = b >> 1;
 15     }
 16     return ans;
 17 }
 18 
 19 inline void mulself(int k) {
 20     memset(C, 0, sizeof(C));
 21     for(int p = 0; p <= k; p++) {
 22         for(int j = 0; j <= k; j++) {
 23             for(int i = 0; i <= k; i++) {
 24                 (C[i][j] += 1ll * A[i][p] * A[p][j] % MO) %= MO;
 25             }
 26         }
 27     }
 28     memcpy(A, C, sizeof(A));
 29     return;
 30 }
 31 
 32 inline void mul(int k) {
 33     memset(C, 0, sizeof(C));
 34     for(int p = 0; p <= k; p++) {
 35         for(int j = 0; j <= k; j++) {
 36             for(int i = 0; i <= k; i++) {
 37                 (C[i][j] += 1ll * ANS[i][p] * A[p][j] % MO) %= MO;
 38             }
 39         }
 40     }
 41     memcpy(ANS, C, sizeof(C));
 42     return;
 43 }
 44 
 45 inline int cal(int k) {
 46     if(k < 0) return 0;
 47     if(k == 0) return qpow(1 - q + MO, n);
 48     memset(f, 0, sizeof(f));
 49     memset(g, 0, sizeof(g));
 50 
 51     for(int i = 0; i <= k + 1; i++) {
 52         g[0][i] = 1;
 53     }
 54 
 55     for(int i = 1; i <= k; i++) {
 56         for(int j = k / i; j >= 0; j--) {
 57             /// g[i][j]
 58             g[i][j] = g[i][j + 1];
 59             for(int p = 1; p <= i; p++) {
 60                 (g[i][j] += 1ll * g[p - 1][j + 1] * g[i - p][j] % MO * pw[j] % MO * (1 - q + MO) % MO) %= MO;
 61             }
 62             //printf("g %d %d = %d \n", i, j, g[i][j]);
 63         }
 64     }
 65 
 66     //puts("");
 67 
 68     /// cal f
 69     if(n <= 1000) {
 70         f[0] = 1;
 71         for(int i = 1; i <= n; i++) {
 72             /// f[i]
 73             if(i <= k) f[i] = g[i][1];
 74             for(int j = std::max(1, i - k); j <= i; j++) {
 75                 (f[i] += 1ll * f[j - 1] * (1 - q + MO) % MO * g[i - j][1] % MO) %= MO;
 76             }
 77             //printf("f %d = %d \n", i, f[i]);
 78         }
 79         return f[n];
 80     }
 81     else {
 82         memset(ANS, 0, sizeof(ANS));
 83         for(int i = 0; i <= k; i++) {
 84             ANS[i][i] = 1;
 85         }
 86         memset(A, 0, sizeof(A));
 87         for(int i = 0; i < k; i++) {
 88             A[i + 1][i] = 1;
 89         }
 90         for(int i = 0; i <= k; i++) {
 91             A[i][k] = 1ll * g[k - i][1] * (1 - q + MO) % MO;
 92         }
 93         int b = n - k;
 94         while(b) {
 95             if(b & 1) {
 96                 mul(k);
 97             }
 98             mulself(k);
 99             b = b >> 1;
100         }
101         /// mul g ans
102         int ans = 0;
103         for(int i = 0; i <= k; i++) {
104             (ans += 1ll * g[i][0] * ANS[i][k] % MO) %= MO;
105         }
106         return ans;
107     }
108 }
109 
110 /*
111 2 2 1 2
112 */
113 
114 int main() {
115     int x, y;
116     scanf("%d%d%d%d", &n, &K, &x, &y);
117     q = 1ll * x * qpow(y, MO - 2) % MO;
118     //printf("q = %d \n", q);
119     pw[0] = 1;
120     for(int i = 1; i <= K; i++) {
121         pw[i] = 1ll * pw[i - 1] * q % MO;
122     }
123 
124     if(n == 1) {
125         int ans = 1ll * qpow(q, K) * (1 - q + MO) % MO;
126         printf("%d\n", ans);
127         return 0;
128     }
129 
130     int ans = (cal(K) - cal(K - 1) + MO) % MO;
131     printf("%d\n", ans);
132 
133     return 0;
134 }
90分代碼

 

棄療了棄療了...

相關文章
相關標籤/搜索