传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1910

这就是noi2013 penman 的简化版嘛,只有一个I的话,dp就简单很多了,我们发现I是由3个小矩形组成的,所以我们一行一行dp,

枚举它属于哪一个矩形,左边界和右边界就行了,至于矩形间的转移,再用一个g数组保存上一个矩形的最大值就行了。

第一次做图形dp,感觉就是要把握住图形的特点,再充分利用各种条件优化就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define X(x) ((x) > 0 ? (x) : 0)
const int maxn = 210;
int f[3][2][maxn][maxn], g[2][maxn][maxn];
int a[maxn][maxn];
int n, m, ans;
void update(int &x, int y, int z) {
    if(y == -1) return;
    x = max(x, y + z);
    return;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            scanf("%d", &a[i][j]);
        }
    }
    memset(f, -1, sizeof(f));
    memset(g, -1, sizeof(g));
    memset(f[0][0], 0, sizeof(f[0][0]));
    for(int x = 1; x <= n; x ++) {
        for(int i = 0; i < 3; i ++) memset(f[i][x & 1], -1, sizeof(f[i][x & 1]));
        for(int l = 1; l <= m; l ++) {
            if(a[x][l]) continue;
            for(int r = l; r <= m; r ++) {
                if(a[x][r]) break;
                update(f[0][x & 1][l][r], X(f[0][(x - 1) & 1][l][r]), (r - l + 1));
                update(f[1][x & 1][l][r], f[1][(x - 1) & 1][l][r], (r - l + 1));
                if(l > 1 && r < m) update(f[1][x & 1][l][r], g[0][l - 1][r + 1], (r - l + 1));
                update(f[2][x & 1][l][r], f[2][(x - 1) & 1][l][r], (r - l + 1));
                if(l + 1 < r) update(f[2][x & 1][l][r], g[1][l + 1][r - 1], (r - l + 1));
                update(ans, f[2][x & 1][l][r], 0);
            }
        }
        memset(g, -1, sizeof(g));
        for(int len = m; len ; len --) {
            for(int l = 1; l + len - 1 <= m; l ++) {
                int r = l + len - 1, t = -1;
                if(l > 1) t = max(t, g[0][l - 1][r]);
                if(r < m) t = max(t, g[0][l][r + 1]);
                g[0][l][r] = max(f[0][x & 1][l][r], t);
            }
        }
        for(int len = 1; len <= m; len ++) {
            for(int l = 1; l + len - 1 <= m; l ++) {
                int r = l + len - 1, t = -1;
                if(l < r) t = max(t, g[1][l + 1][r]);
                if(l < r) t = max(t, g[1][l][r - 1]);
                g[1][l][r] = max(f[1][x & 1][l][r], t);
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}