LOJ#2668 书法家

题意:要在一张网格纸上画出NOI图形,使得所占格子的权值和最大。

解:暴力DP即可...

从左往右,每个字母都可以被划分成三块,且每块都可用上下两维来表示。

于是一块一块的DP。考虑如何O(1)转移。显然只有N的中间那一块不好转移,别的都是直接转移。

N的三块的两个连接处之间,可以枚举必须持平的那个端点,另一个用前缀最值。

N第二块内部,考虑枚举后一个矩形的上边界,逐步扩展下边界。此时发现每扩展一步,可能的决策集合会增加:左边一格,下边界为刚扩展的那一格,上边界在枚举的上边界以上的所有状态。

于是对于每个下边界,预处理出上边界从上到下的一个前缀最值,加到决策集合里取max即可。

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

 

posted @ 2019-04-27 12:35  huyufeifei  阅读(151)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

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