【bzoj5085】最大 二分+暴力

本文介绍了一个关于寻找矩阵中子矩形的问题,目标是最小值最大化。通过二分查找结合暴力枚举的方法来解决该问题,详细阐述了算法思路及实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

给你一个n×m的矩形,要你找一个子矩形,价值为左上角左下角右上角右下角这四个数的最小值,要你最大化矩形的价值。

输入

第一行两个数n,m,接下来n行每行m个数,用来描述矩形
n, m ≤ 1000

输出

输出一个数表示答案

样例输入

2 2
1 2
3 4

样例输出

1


题解

二分+暴力

首先题目问的是最小值最大,显然二分答案,问题转化为判断是否存在一个子矩形,满足四个角的权值大于等于mid。

考虑暴力怎么做:枚举所有与x轴平行的线段(即同行的线段),判断是否有两个线段的端点横坐标相同(即列数相同)。

由于只要有任何一种线段出现次数大于等于2即可行,因此最坏情况下每一种线段也只出现了一次。

因为线段只有 $m^2$ 个,所以只需要使用严格的复杂度把所有线段暴力找出来即可。这样最坏情况下时间复杂度不会超过 $O(nm+m^2)$

因此总的时间复杂度为 $O((n+m)^2\log n)$ 

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1010
using namespace std;
int n , m , a[N][N] , c[N][N] , v[N] , tot;
bool solve(int mid)
{
    int i , j , k;
    for(i = 1 ; i <= m ; i ++ )
        for(j = i + 1 ; j <= m ; j ++ )
            c[i][j] = 0;
    for(i = 1 ; i <= n ; i ++ )
    {
        tot = 0;
        for(j = 1 ; j <= m ; j ++ )
            if(a[i][j] >= mid)
                v[++tot] = j;
        for(j = 1 ; j <= tot ; j ++ )
        {
            for(k = j + 1 ; k <= tot ; k ++ )
            {
                if(c[v[j]][v[k]]) return 1;
                c[v[j]][v[k]] = 1;
            }
        }
    }
    return 0;
}
int main()
{
    int i , j , l = 1 << 30 , r = 0 , mid , ans;
    scanf("%d%d" , &n , &m);
    for(i = 1 ; i <= n ; i ++ )
        for(j = 1 ; j <= m ; j ++ )
            scanf("%d" , &a[i][j]) , l = min(l , a[i][j]) , r = max(r , a[i][j]);
    while(l <= r)
    {
        mid = (l + r) >> 1;
        if(solve(mid)) ans = mid , l = mid + 1;
        else r = mid - 1;
    }
    printf("%d\n" , ans);
    return 0;
}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/7885535.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值