问题 L: Largest Allowed Area ( scanf + 二分 + 前缀和)

题目:

http://icpc.upc.edu.cn/problem.php?cid=1740&pid=11

我的做法确实暴力,,不过他们说的 高级读入挂是什么?  

思路,要找方形的空地, 二分答案,一开始的区间是(1,mini(C,R) ) 也就是(l,r),

找中间值  d=(l+r)/2  拿这个d 去在原图里面暴力找,看看能不能找到一个边长是d 的正方形(通过枚举所有点的方式),找到了就立刻停下,再从(d+1,r)里面找, 要是暴力没找到就从(l,d-1) 找边长

#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
using namespace std;

int forest[1005][1005];
int qsum[1005][1005];
int c,r;
int ans=0;
void erfen(int a,int b)
{

    int d=(a+b)/2;
    bool flag=0;
    for(int i=0;i<c;i++){
        for(int j=0;j<r;j++)
        {
            if( j+d<r && i+d<c){

                int qq=qsum[i+d][j+d];
                if(i-1>=0)
                    qq-=qsum[i-1][j+d];
                if(j-1>=0 )
                    qq-=qsum[i+d][j-1];

                if(i-1>=0 && j-1>=0)
                    qq+=qsum[i-1][j-1];

                if(qq <=1  )
                {
//                    cout<<"起点在这   "<<i+1<<"      "<<j+1<<endl;
                    flag=1;
                    break;
                }
            }


        }
        if(flag==1) break;
    }
    if(a==d && flag==0) {ans=a-1;  return ;}
    if( a==b && flag==1) {ans=a;    return ;}
    if(flag==0) {  erfen(a,d-1);}
    if(flag==1) {   erfen(d+1,b);}
}


int main()
{
    int t;  scanf("%d",&t);
    while(t--){
        ans=0;
       // memset(qsum,0,sizeof qsum);

       scanf("%d%d",&c,&r);

       for(int i=0;i<c;i++)
       for(int j=0;j<r;j++)
        scanf("%d",&forest[i][j]);


        qsum[0][0]=forest[0][0];

        for(int i=0;i<c;i++){
            int j;
            for( j=0;j<r;j++)
            {
                if(i==0)
                    qsum[i][j]=forest[i][j]+qsum[i][j-1];
                else if(j==0)
                    qsum[i][j]=forest[i][j]+qsum[i-1][j];
                else
                qsum[i][j]=forest[i][j]+qsum[i][j-1]+qsum[i-1][j]-qsum[i-1][j-1];


            }
        }

        erfen(0,min(c,r)-1);


        printf("%d\n",ans+1);

    }

    return 0;
}

简简单单做出来不好吗?非要整些花里胡哨的东西。

开玩笑的,我是个渣渣,写完这篇立刻去学读入挂

916 ms  差点就超时了,幸亏数据水,,好险。

 

学习一下

感觉比我写的思路清楚很多。 --  -- ||

  https://blog.csdn.net/weixin_40636982/article/details/87480294

#include<bits/stdc++.h>
using namespace std;

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 sum[1005][1005], a[1005][1005];

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]);
            }
        }
        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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值