申明
再次申明这个专栏只是分享博主学习算法时的顺序,给新手提供一个入门的好方法(博主现在也是新手所以博主写的代码适合C转C++的新手学习),具体算法逻辑需要自己学习,代码区域有部分解释,因此有错误可以私信或者直接在评论区骂。
前言
上文我们介绍的求一维二维三维子矩阵和的最大值时,我们都用到了压缩维度的思想,实现的方式都为前缀和,请一定要先学会前文再来看这个题,我们同样的思路先把行给压缩了,然后用双指针来求(如果双指针不会的话,可以先练习我在双指针专栏的逛画廊的题)-----这个题如果纯暴力应该是,只使用矩阵前缀和复杂度为
,会超时。
题目链接
P8783 [蓝桥杯 2022 省 B] 统计子矩阵 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=510;
ll n,m,k;
ll arr[N][N];
ll sum[N][N]; //前缀和之后的
ll b[N]; //压缩后的二维数组
ll num=0;
int main()
{
scanf("%lld %lld %lld",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&arr[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sum[i][j]=sum[i][j-1]+arr[i][j];
for(int l=1;l<=m;l++)
{
for(int r=l;r<=m;r++)
{
for(int i=1;i<=n;i++)
{
b[i]=sum[i][r]-sum[i][l-1];
}
ll res=0;
for(int up=1,down=1;down<=n;down++)
{
res+=b[down];
if(res<=k) num+=down-up+1;
else
{
while(res>k)
{
res-=b[up];
up++;
}
num+=down-up+1; //因为此时down和up都变了所以需要加!!!
}
}
}
}
printf("%lld\n",num);
return 0;
}