AcWing 4405. 统计子矩阵
来源:第十三届蓝桥杯省赛C++B组
给定一个 N×MN×M 的矩阵 AA,请你统计有多少个子矩阵 (最小 1×11×1,最大 N×MN×M) 满足子矩阵中所有数的和不超过给定的整数 KK?
输入格式
第一行包含三个整数 N,MN,M 和 KK。
之后 NN 行每行包含 MM 个整数,代表矩阵 AA。
输出格式
一个整数代表答案。
数据范围
对于 30%30% 的数据,N,M≤20N,M≤20,
对于 70%70% 的数据,N,M≤100N,M≤100,
对于 100%100% 的数据,1≤N,M≤500;0≤Aij≤1000;1≤K≤2500000001≤N,M≤500;0≤Aij≤1000;1≤K≤250000000。
输入样例:
3 4 10
1 2 3 4
5 6 7 8
9 10 11 12
输出样例:
19
样例解释
满足条件的子矩阵一共有 1919,包含:
- 大小为 1×11×1 的有 1010 个。
- 大小为 1×21×2 的有 33 个。
- 大小为 1×31×3 的有 22 个。
- 大小为 1×41×4 的有 11 个。
- 大小为 2×12×1 的有 33 个。
子矩阵的和加强版
AcWing 796. 子矩阵的和 (前缀和)_呵呵world的博客-CSDN博客
AC
#include<stdio.h>
#include<iostream>
#define N 503
using namespace std;
int a[N][N];
//s[N][N];
/*long long calc(int x1,int y1,int x2,int y2)//计算以x1,y1为左上角 x2,y2为右下角
{
return a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];
}*/
int main(void)
{
ios::sync_with_stdio(false);
int n,m;
long long k;
long long ans=0;
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
//初始化前缀和数组 即计算左上角为1,1 右下角为i,j的矩阵
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
}
for(int l=1;l<=m;l++)//枚举矩阵的左边
{
for(int r=l;r<=m;r++)//枚举矩阵的右边
{
for(int i=1,j=1;i<=n;i++)//根据已有的边界,开始从上到下双指针扫描
{
//j是上边界 i下边界,如果这一部分>k 就从下一行开始遍历
//calc(j,l,i,r)==> x1,y1,x2,y2
while(j<=i && a[i][r]-a[j-1][r]-a[i][l-1]+a[j-1][l-1]>k) j++;
//当i=1,j=1的时候,该位置的值如果大于k的话,这个时候j+1,就大于i了
if(j<=i) ans+=(i-j+1);//j<=i 所有就证明第j行一定满足条件 i-j+1就代表的是上下界之间一共多少行
}
}
}
cout<<ans<<'\n';
return 0;
}