代码源每日一题div2 巨大的牛棚

巨大的牛棚 - 题目 - Daimayuan Online Judge

题意:

农夫约翰想要在他的正方形农场上建造一座正方形大牛棚。他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方。我们假定,他的农场划分成 n * n的方格。输入数据中包括有树的方格的列表。你的任务是计算并输出,在他的农场中,不需要砍树却能够修建的最大正方形牛棚。牛棚的边必须和水平轴或者垂直轴平行。 考虑下面的方格,它表示农夫约翰的农场,‘.'表示没有树的方格,‘#'表示有树的方格

思路:

一开始的思路是枚举两个点,然后二维前缀和判中间是否有树,注意到数据范围O(n^4)超时

因此就想枚举一个点和枚举边长,降到O(n^3),但是1e9还是超时

枚举超时,我们就考虑二分

我们考虑二分边长

注意到,边长过大就会包含树,边长过小就不会包含树

因此边长具有单调性,因此二分是合理的

接下来就是写check函数,那就是用二维前缀和判正方形中间是否有树了

Code:

#include <bits/stdc++.h>
using namespace std;
const int mxn=1e3+10;
int n,T,x,y,ans;
int a[mxn][mxn],f[mxn][mxn];
bool check(int x){
    for(int i=1;i<=n-x+1;i++){
        for(int j=1;j<=n-x+1;j++){
            int x1=j,y1=i,x2=j+x-1,y2=i+x-1;
            if(f[x2][y2]-f[x1-1][y2]-f[x2][y1-1]+f[x1-1][y1-1]==0) return true;
        }
    }
    return false;
}
int main(){
    scanf("%d%d",&n,&T);
    memset(a,0,sizeof(a));
    memset(f,0,sizeof(f));
    while(T--){
        scanf("%d%d",&x,&y);
        a[x][y]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            f[i][j]=a[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
        }
    }
    int l=1,r=1e9;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)){
            ans=mid;
            l=mid+1;
        }else r=mid-1;
    }
    printf("%d\n",ans);
}

总结:

算法:

1.判断二维平面上矩形中间是否为空,用二维前缀和即可

2.什么时候考虑二分:

最大值最小或最小值最大的时候

我们不知道这个值是多少的时候

枚举超时的时候

求最值的时候

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值