題意:有一個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 }
因而咱們來個矩陣快速冪優化,得到了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 }
棄療了棄療了...