題意:要在一張網格紙上畫出NOI圖形,使得所佔格子的權值和最大。c++
解:暴力DP便可...ide
從左往右,每一個字母均可以被劃分紅三塊,且每塊均可用上下兩維來表示。spa
因而一塊一塊的DP。考慮如何O(1)轉移。顯然只有N的中間那一塊很差轉移,別的都是直接轉移。code
N的三塊的兩個鏈接處之間,能夠枚舉必須持平的那個端點,另外一個用前綴最值。blog
N第二塊內部,考慮枚舉後一個矩形的上邊界,逐步擴展下邊界。此時發現每擴展一步,可能的決策集合會增長:左邊一格,下邊界爲剛擴展的那一格,上邊界在枚舉的上邊界以上的全部狀態。get
因而對於每一個下邊界,預處理出上邊界從上到下的一個前綴最值,加到決策集合裏取max便可。it
1 #include <bits/stdc++.h> 2 3 const int INF = 0x3f3f3f3f; 4 5 #define g f[FLAG] 6 #define h f[FLAG ^ 1] 7 8 int f[2][510][155][155], FLAG, n, m; 9 int s[155][510], p[510], temp[155][155]; 10 11 inline int getSum(int i, int l, int r) { 12 if(l > r) return 0; 13 return s[r][i] - s[l - 1][i]; 14 } 15 16 inline void out() { 17 for(int i = 1; i <= m; i++) { 18 for(int up = 1; up <= n; up++) { 19 for(int down = up; down <= n; down++) { 20 printf("%d ", g[i][up][down]); 21 } 22 } 23 puts(""); 24 } 25 puts(""); 26 return; 27 } 28 29 inline void outp() { 30 printf("p : "); 31 for(int i = 1; i <= m; i++) { 32 printf("%d ", p[i]); 33 } 34 puts(""); 35 puts(""); 36 return; 37 } 38 39 int main() { 40 //printf("%d \n", sizeof(f) / 1048576); 41 42 scanf("%d%d", &n, &m); 43 for(int i = 1; i <= n; i++) { 44 for(int j = 1; j <= m; j++) { 45 scanf("%d", &s[i][j]); 46 s[i][j] += s[i - 1][j]; 47 } 48 } 49 50 FLAG = 1; /// N 1 51 memset(g, ~0x3f, sizeof(g)); 52 for(int i = 1; i <= m; i++) { 53 for(int up = 1; up < n; up++) { 54 for(int down = up + 1; down <= n; down++) { 55 g[i][up][down] = std::max(0, g[i - 1][up][down]) + getSum(i, up, down); 56 } 57 } 58 } 59 60 //out(); 61 62 FLAG ^= 1; /// N 1.5 63 memset(g, ~0x3f, sizeof(g)); 64 for(int i = 1; i <= m; i++) { 65 for(int up = 1; up < n; up++) { 66 int large = -INF; 67 for(int down = n - 1; down >= up; down--) { 68 large = std::max(large, h[i - 1][up][down + 1]); 69 g[i][up][down] = large + getSum(i, up, down); 70 } 71 } 72 } 73 74 //out(); 75 76 FLAG ^= 1; /// N 2 77 //memset(g, ~0x3f, sizeof(g)); 78 memcpy(g, h, sizeof(h)); 79 for(int i = 1; i <= m; i++) { 80 memset(temp, ~0x3f, sizeof(temp)); 81 for(int down = 1; down <= n; down++) { 82 for(int up = 1; up <= down; up++) { 83 temp[down][up] = std::max(temp[down][up - 1], std::max(g[i - 1][up][down], h[i - 1][up][down])); 84 } 85 } 86 for(int up = 1; up <= n; up++) { 87 int large = temp[up - 1][up - 1]; 88 for(int down = up; down <= n; down++) { 89 large = std::max(large, temp[down][up]); 90 g[i][up][down] = std::max(large + getSum(i, up, down), h[i][up][down]); 91 } 92 } 93 } 94 95 //out(); 96 97 FLAG ^= 1; /// N 2.5 98 memset(g, ~0x3f, sizeof(g)); 99 for(int i = 1; i <= m; i++) { 100 for(int down = 2; down <= n; down++) { 101 int large = -INF; 102 for(int up = down - 1; up >= 1; up--) { 103 large = std::max(large, h[i - 1][up + 1][down]); 104 g[i][up][down] = large + getSum(i, up, down); 105 } 106 } 107 } 108 109 //out(); 110 111 FLAG ^= 1; /// N 3 112 memset(g, ~0x3f, sizeof(g)); 113 for(int i = 1; i <= m; i++) { 114 for(int up = 1; up < n; up++) { 115 for(int down = up + 1; down <= n; down++) { 116 g[i][up][down] = std::max(h[i][up][down], g[i - 1][up][down] + getSum(i, up, down)); 117 } 118 } 119 } 120 121 //out(); 122 123 /// get p : max of g 124 memset(p, ~0x3f, sizeof(p)); 125 for(int i = 1; i <= m; i++) { 126 p[i] = p[i - 1]; 127 for(int up = 1; up <= n; up++) { 128 for(int down = 1; down <= n; down++) { 129 p[i] = std::max(p[i], g[i][up][down]); 130 } 131 } 132 } 133 134 //outp(); 135 136 //out(); 137 138 //printf(" O 1 \n"); 139 140 FLAG ^= 1; /// O 1 141 memset(g, ~0x3f, sizeof(g)); 142 for(int i = 5; i <= m; i++) { 143 for(int up = 1; up < n - 1; up++) { 144 for(int down = up + 2; down <= n; down++) { 145 g[i][up][down] = p[i - 2] + getSum(i, up, down); 146 } 147 } 148 } 149 150 //out(); 151 152 //printf(" O 2 \n"); 153 154 FLAG ^= 1; /// O 2 155 memset(g, ~0x3f, sizeof(g)); 156 for(int i = 1; i <= m; i++) { 157 for(int up = 1; up < n - 1; up++) { 158 for(int down = up + 2; down <= n; down++) { 159 g[i][up][down] = std::max(h[i - 1][up][down], g[i - 1][up][down]) + getSum(i, up, up) + getSum(i, down, down); 160 } 161 } 162 } 163 164 //out(); 165 166 FLAG ^= 1; /// O 3 167 memset(g, ~0x3f, sizeof(g)); 168 for(int i = 1; i <= m; i++) { 169 for(int up = 1; up < n - 1; up++) { 170 for(int down = up + 2; down <= n; down++) { 171 g[i][up][down] = h[i - 1][up][down] + getSum(i, up, down); 172 } 173 } 174 } 175 176 //out(); 177 178 /// get p : max of g 179 memset(p, ~0x3f, sizeof(p)); 180 for(int i = 1; i <= m; i++) { 181 p[i] = p[i - 1]; 182 for(int up = 1; up < n - 1; up++) { 183 for(int down = up + 2; down <= n; down++) { 184 p[i] = std::max(p[i], g[i][up][down]); 185 } 186 } 187 } 188 189 //outp(); 190 191 //out(); 192 193 FLAG ^= 1; /// I 1 194 memset(g, ~0x3f, sizeof(g)); 195 for(int i = 5; i <= m; i++) { 196 for(int up = 1; up < n - 1; up++) { 197 for(int down = up + 2; down <= n; down++) { 198 g[i][up][down] = std::max(p[i - 2], g[i - 1][up][down]) + getSum(i, up, up) + getSum(i, down, down); 199 } 200 } 201 } 202 203 //out(); 204 205 FLAG ^= 1; /// I 2 206 memset(g, ~0x3f, sizeof(g)); 207 for(int i = 1; i <= m; i++) { 208 for(int up = 1; up < n - 1; up++) { 209 for(int down = up + 2; down <= n; down++) { 210 g[i][up][down] = std::max(g[i - 1][up][down], h[i - 1][up][down]) + getSum(i, up, down); 211 } 212 } 213 } 214 215 //out(); 216 int ans = -INF; 217 218 FLAG ^= 1; /// I 3 219 memset(g, ~0x3f, sizeof(g)); 220 for(int i = 1; i <= m; i++) { 221 for(int up = 1; up < n - 1; up++) { 222 for(int down = up + 2; down <= n; down++) { 223 g[i][up][down] = std::max(g[i - 1][up][down], h[i - 1][up][down]) + getSum(i, up, up) + getSum(i, down, down); 224 ans = std::max(g[i][up][down], ans); 225 } 226 } 227 } 228 229 //out(); 230 231 printf("%d\n", ans); 232 return 0; 233 }