• 洛谷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 }
  • 相关阅读:
    Python笔记_函数,模块,包的关系
    「GXOI / GZOI2019」宝牌一大堆
    「BalticOI 2020」村庄 (贪心)
    CF Round #635 Div.1 Chiori and Doll Picking (hard version)
    「BalticOI 2020」病毒
    「BalticOI 2020」小丑
    「BalticOI 2020」混合物
    k短路
    「JSOI2019」神经网络
    「NOI2020」时代的眼泪
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10600545.html
Copyright © 2020-2023  润新知