洛谷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
", 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
", ans);
47     return 0;
48 }
原文地址:https://www.cnblogs.com/AlphaWA/p/10600545.html