Largest Allowed Area(二维差分+二分+读入挂)

题目:2018 ICPC Asia Nakhon Pathom Regional Contest Problem L Largest Allowed Area 

题意描述:

        一家公司想找一块正方形的地来建设总部,这块地只能包含一块林地。即给你n和m,表示地的长和宽。接下来给你nxm的矩阵,矩阵元素由0和1组成。0表示空地,1表示林地。要你从这块地中选出一个最大的正方形的地,这块地中最多只能包含一块林地。输出这个正方形的边长。

题目分析:

       因为这块地中最多可以包含一块林地,所以可以用二维差分来判断一块地中有多少个林地。而这道题n和m的范围都是1000,而且想要的地是正方形,所以我们用二分来判断到某个点可以得到的最大正方形,时间复杂度为n^2*logn.这道题目的输入样例有20,那最坏的情况为20*1000*1000 = 2E7.输入比较大,所以还要用到输入挂来优化输入,而且用一般的读入挂还不行,我试了几个读入挂了,只有下面这个可以,不过下面这个读入挂本地是跑不出结果的。(做的是时候就是卡这里了,咕咕)。

代码:

#include<bits/stdc++.h>
using namespace std;
int sum[1005][1005], a[1005][1005];

namespace fastIO {
    #define BUF_SIZE 100000
    //fread -> read
    bool IOerror = 0;
    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if(p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if(pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }
    inline bool blank(char ch) {
        return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
    }
    inline void read(int &x) {
        char ch;
        while(blank(ch = nc()));
        if(IOerror) return;
        for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }
    #undef BUF_SIZE
};
using namespace fastIO;

int max(int x, int y){
    return x > y ? x : y;
}

int min(int x, int y){
    return x < y ? x : y;
}

int func(int x, int y, int s){
    int l = 1, r = s, mid = (l+r)/2, ans = 1;
    while(r >= l){
        mid = (l+r)/2;
        if((sum[x][y]-sum[x-mid][y]-sum[x][y-mid]+sum[x-mid][y-mid] <= 1) ) l = mid+1, ans = mid;
        else r = mid-1;
    }
    return ans;
}
int main()
{
    int t, n, m;
    read(t);
    while(t--){
        read(n);
        read(m);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                 read(a[i][j]);
    //            scan_d(a[i][j]);
   //             scanf("%d", &a[i][j]);
            }
        }
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
            }
        }
        int ans = 0;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                int d = min(i, j);
                ans = max(ans, func(i, j, d));
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值