洛谷1736(二维dp+预处理)
洛谷1387的进阶版,但很像。
1387要求是“全为1的正方形”,取dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))吧?这个有“只有对角线可以有1”的要求,取的是dp[i][j] = min(dp[i-1][j-1], min(s1[i-1][j], s2[i][j-1])),s1s2是预处理的两个数组,表示上方和左方有多少连续的0.另外本题左右方向对角线都算,所以得算两遍。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 2550; 7 int n, m, ans, a[maxn][maxn]; 8 int s1[maxn][maxn], s2[maxn][maxn], dp[maxn][maxn]; 9 10 int main() { 11 scanf("%d %d", &n, &m); 12 for (int i = 1; i <= n; i++) { 13 for (int j = 1; j <= m; j++) { 14 scanf("%d", &a[i][j]); 15 } 16 } 17 18 for (int i = 1; i <= n; i++) { 19 for (int j = 1; j <= m; j++) { 20 if (!a[i][j]) { 21 s1[i][j] = s1[i-1][j] + 1;//up 22 s2[i][j] = s2[i][j-1] + 1;//left 23 } else { 24 dp[i][j] = min(dp[i-1][j-1], min(s1[i-1][j], s2[i][j-1])) + 1; 25 ans = max(ans, dp[i][j]); 26 } 27 } 28 } 29 memset(dp, 0, sizeof dp); 30 memset(s2, 0, sizeof s2); 31 for (int i = 1; i <= n; i++) { 32 for (int j = m; j; j--) { 33 if (!a[i][j]) s2[i][j] = s2[i][j+1] + 1;//right 34 else { 35 dp[i][j] = min(dp[i-1][j+1], min(s1[i-1][j], s2[i][j+1])) + 1; 36 ans = max(ans, dp[i][j]); 37 } 38 } 39 } 40 41 printf("%d\n", ans); 42 return 0; 43 }
而我自己做时……我这种满脑子二分前缀和的暴力分子大概没救了吧~不过这两种做法时间和空间上相差不多,反而是暴力快一点(逃
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 int n, m, ans; 7 int a[2550][2550], b[2550][2550], sum1[2550][2550], sum2[2550][2550], dp[2][2550]; 8 9 void DP(int a[][2550], int sum[][2550]) { 10 for (int i = 1; i <= n; i++) { 11 for (int j = 1; j <= m; j++) { 12 if (a[i][j]) { 13 auto ok = [](int i, int j, int tmp, int sum[][2550]) { 14 return sum[i][j] - sum[i - tmp][j] - sum[i][j - tmp] + sum[i - tmp][j - tmp] == tmp; 15 }; 16 int l = 1, r = dp[(i - 1)&1][j - 1] + 1, t; 17 while (l <= r) { 18 int mid = (l + r) >> 1; 19 if (ok(i, j, mid, sum)) { 20 t = mid; 21 l = mid + 1; 22 } else r = mid - 1; 23 } 24 dp[i&1][j] = t; 25 } else dp[i&1][j] = 0; 26 ans = max(ans, dp[i&1][j]); 27 } 28 } 29 } 30 31 int main() { 32 scanf("%d %d", &n, &m); 33 for (int i = 1; i <= n; i++) 34 for (int j = 1; j <= m; j++) { 35 scanf("%d", &a[i][j]); 36 b[i][m - j + 1] = a[i][j]; 37 } 38 for (int i = 1; i <= n; i++) 39 for (int j = 1; j <= m; j++) { 40 sum1[i][j] = sum1[i - 1][j] + sum1[i][j - 1] - sum1[i - 1][j - 1] + a[i][j]; 41 sum2[i][j] = sum2[i - 1][j] + sum2[i][j - 1] - sum2[i - 1][j - 1] + b[i][j]; 42 } 43 DP(a, sum1); 44 memset(dp, 0, sizeof dp); 45 DP(b, sum2); 46 printf("%d\n", ans); 47 return 0; 48 }