crf 的视察(二分+二维前缀和)

1.1 Description
crf 拥有一个王国。
他的王国是长方形的,跨越了n 个纬度区和m 个经度区,且在每个经度区和纬度区的交界处
有一座城市(即crf 的王国一共有n  m 座城市)。
某一天早上,crf 从他的一万平方米的大床上起来,他决定去视察一下他的王国,去查看一下
他的全民刷题计划的实施情况。
消息一出,全王国各城市的市长们都吓到了,因为有一些市长偷懒还没有宣布crf 的全民刷题
计划,所以全体市长集体开了个会,讨论要怎样才能让crf 不发现他们的不作为。
他们知道crf 有个坏习惯,他只会视察一个正方形区域的城市,而他们也知道视察了越多的城
市,crf 就会越开心。但一旦crf 发现他视察的城市他的政策没有贯彻下去,他就会非常愤怒,然后
把这些市长发配去养猪。
市长们现在想找出来一个最大正方形,使得在这个正方形内的所有城市都已经贯彻了crf 的全
民刷题计划。
1.2 Input
输入的第一行为两个整数n;m,表示crf 王国横跨的纬度区数量和经度区数量。
接下来n 行,每行有m 个整数,每个整数只可能为0 或者1,0 表示这个城市没有贯彻crf 的
全民刷题计划,1 表示已经贯彻。
1.3 Output
输出一个数字k,为最大的正方形的边长。
1.4 Sample
Sample Input Sample Output
3 3
0 1 1
1 1 1
1 1 1
2
1.5 Hint
对于30% 的数据,保证1≤  n,m ≤30。
对于100% 的数据,保证1≤  n,m≤ 2000。


解题思路:

首先二分边长长度为mid,n方枚举左上端点,利用二维前缀和统计以mid值为边长的正方形内0的个数,若0的个数为0,则成立,否则枚举下一个左上端点

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N = 2010;
int n, m;
int mapp[N][N];
int cnt[N][N];
inline int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool judge(int x){
    for(int i=1; i+x-1<=n; i++)
        for(int j=1; j+x-1<=m; j++)
            if(cnt[i+x-1][j+x-1] - cnt[i+x-1][j-1] - cnt[i-1][j+x-1] + cnt[i-1][j-1] == 0) return 1;
    return 0;
}
int main(){
    freopen ("inspect.in", "r", stdin);
    freopen ("inspect.out", "w", stdout);
    scanf("%d%d", &n ,&m);
    for(register int i=1; i<=n; i++){
        for(register int j=1; j<=m; j++){
            scanf("%d",mapp[i][i]);
            mapp[i][j]^=1;
            cnt[i][j] = (cnt[i-1][j] + cnt[i][j-1] - cnt[i-1][j-1] + mapp[i][j]);      
        }
    }
    int l=0, r=2000;
    while(l < r){
        int mid = ((l + r) >> 1) + 1;
        if(judge( mid ) ) l=mid;
        else r = mid - 1;
    }
    printf("%d", l);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/tonyshen/p/11369655.html
CRF