1 条题解

  • 0
    @ 2025-8-24 21:18:26

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Dongze2010
    这里只留下了二十二个字,记得看主页(标点符号不算)

    搬运于2025-08-24 21:18:25,当前版本为作者最后更新于2025-05-20 17:38:27,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    B4293B4293 奖品

    题目大意

    给你一个 n×mn \times m二进制矩阵,找到一个最大的正方形,使得这个正方形对角线所对应的数都为 11

    题目分析

    不用前缀和,直接查找的时间复杂度约为 O(N5)O(N^5)

    所以最好使用前缀和。我们可以通过前缀和或动态规划,将复杂度降至 O(N3)O(N^3) 或更低。(其实标签里面就有前缀和。)

    若有二维 ai,ja_{i,j} 数组。

    6 1 3 4
    2 4 5 3
    5 1 2

    其对应的 sumi,jsum_{i,j} 。 |6|7|10|14| |:-:|:-:|:-:|:-:| |8|13|21|28| |13|19|29|39|

    二维前缀和计算。

    cin >> a[i][j]; //输入
    sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j];
    //计算二维前缀和
    

    输入并计算前缀和

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 114;
    int n,m,a[maxn][maxn],sum[maxn][maxn];
    int main(){
        cin >> n >> m;
        for (int i = 1;i <= n;i++){
            for (int j = 1;j <= m;j++){
                cin >> a[i][j];
                sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j];
            }
        }
        return 0;
    }
    

    接下来的判断怎么写呢?

    我们可以从正方形对角线入手。

    因为一个点若在正方形的对角线上,它就既可以当做这个正方形的左上(下)点,或右上(下)点。这里为遍历方便,只考虑正方形的左上和右上点。

    ai,j=1a_{i,j}=1 且为这个正方形的左上角时,设 x,yx,y 是它的右下方、正方形对角线上的点。若 x,yx,y 没越界且为 11 时,贪心一下,继续往下找。

    while (x <= n and y <= m and a[x][y]
        and sum[x][y] - sum[i-1][y] - sum[x][j-1] + sum[i-1][j-1] == tot + 1){
        tot++; x++; y++; // && = and 个人习惯
    }
    

    ai,j=1a_{i,j}=1 且为这个正方形的右上角时,寻找左下方符合条件的点。

    while (x <= n and y > 0 and a[x][y]
        and sum[x][j] - sum[i-1][j] - sum[x][y-1] + sum[i-1][y-1] == tot + 1){
        tot++; x++; y--;
    }
    

    最后记得保存最大奖品数量。

    res = max(res,tot);
    

    恭喜你,完成啦!

    (记得 return 0; 哦)

    AC Code

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 114;
    int n,m,a[maxn][maxn],sum[maxn][maxn],res = -1,tot; // res 设为一个小于0的,方便后面max
    int main(){
        cin >> n >> m;
        for (int i = 1;i <= n;i++){
            for (int j = 1;j <= m;j++){
                cin >> a[i][j];
                sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j];
            }
        }
        //前缀和
    
        if (!sum[n][m])  {cout << 0 << endl; return 0;}  // 特判
    
        for (int i = 1;i <= n;i++){
            for (int j = 1;j <= m;j++){
                if (!a[i][j]) continue; //优化
                else {
                    int x = i,y = j;
                    while (x <= n and y <= m and a[x][y] and sum[x][y] - sum[i-1][y] - sum[x][j-1] + sum[i-1][j-1] == tot + 1){
                        tot++; x++; y++;
                    }
                    res = max(res,tot);
                    tot = 0; x = i; y = j;
    				while (x <= n and y > 0 and a[x][y] and sum[x][j] - sum[i-1][j] - sum[x][y-1] + sum[i-1][y-1] == tot + 1){
    					tot++; x++; y--;
                    }
    				res = max(res,tot);
    				tot = 0;
                }
            }
        }
        cout << res << endl;
        return 0;
    }
    

    (管理员别卡555)。

    第一次写题解,给个赞,谢谢了。

    • 1

    信息

    ID
    11876
    时间
    1000ms
    内存
    512MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者