题解 洛谷P1387 【最大正方形】

发现大家都是用动归和搜索,我就来一发前缀和!!!

“前缀和可以是数列,也可以是矩阵。

以一个小题为例:给定n个数a[i]以及m个询问并每次询问一段区间的和。要求:一个O(n+m)的做法。

要求效率如此之高,看来,强大的树状数组和线段树也无能为力了。

那么如此一来,前缀和上场了。

若想时间复杂度控制在O(n+m),光读一遍就需要O(n),即每一个询问要求效率为O(1),可怕~~

但前缀和可以做到,开两个数组a[n]和s[n],前者装数据,后者装前n项和。

若想求一段区间[l,r]的和,只需用s[r]-s[l],即可解决。”————摘自CSDN博客 前缀和维护

其实前缀和是一种很方便的东西,所以说本题就可以用前缀和,判定一个正方形是否全是1。

老规矩,首先上变量:

int s[105][105];//记录矩阵的数组
int a[105][105];//记录前缀和的数组
int n,m;//记录矩阵的大小

 

由于矩阵是二维的,所以前缀和与一维的不太一样

for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    {
        a[i][j]=s[i][j]+a[i][j-1]+a[i-1][j]-a[i-1][j-1];
        //由于a[i-1][j-1]被加了两遍,所以减回去
    }

 

其实就是该位置到左上方点形成的矩阵中1的个数。

然后就可以三重循环遍历了:

for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)

        if(s[i][j]!=1)
        continue;//不是1的不用看了
        for(int k=2;i-k>=0&&j-k>=0;++k)
        {
            if(a[i][j]+a[i-k][j-k]-a[i-k][j]-a[i][j-k]==k*k)//关键
            if(k>ans)
            ans=k;
        }
    }

 

关键的,其实就是如何计算正方形中1的个数了,这里要注意:因为计算一个矩阵1的个数时,可能会有些问题:

0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1(矩阵)

比如计算加粗体的正方形的1的个数

0 0 0 0 0
0 0 1 2 3
0 1 3 5 6
0 1 4 7 8
0 2 6 9 11(前缀和)

大家可能会以为是1+5-2-3=1,很明显不对,其实是1 * 1的矩阵(在5所在的位置)的1的个数

但其实这样的:

0 0 0 0 0
0 0 1 2 3
0 1 3 5 6
0 1 4 7 8
0 2 6 9 11(前缀和)

是0+5-0-1=4,就正确了,就是右下角的所在行列分别减去正方形的边长,再一起减去正方形的边长(就像这样a[i][j]+a[i-k][j-k]-a[i-k][j]-a[i][j-k])就是计算正方形1个数所需的4个点

但很明显,这样的3重循环是会超时的,所以就需要优化:

for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    {
        if(s[i][j]!=1)
        continue;
        for(int k=ans+1/*直接遍历比当前答案大的数*/;i-k>=0&&j-k>=0;++k)
        {
            if(a[i][j]+a[i-k][j-k]-a[i-k][j]-a[i][j-k]==k*k)
            ans=k;
            else
            break;
            //如果小的正方形不行了,比他大的但有包含它的正方形肯定不行
        }
    }

 

最后将程序拼凑在一起加上必要的输入输出,就可以ac了

2018-4-20

转载于:https://www.cnblogs.com/Point-King/p/9740842.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值