P8783 [蓝桥杯 2022 省 B] 统计子矩阵

249 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情

[蓝桥杯 2022 省 B] 统计子矩阵

题目描述

给定一个 N×MN \times M 的矩阵 AA,请你统计有多少个子矩阵 (最小 1×11 \times 1, 最大 N×M)N \times M) 满足子矩阵中所有数的和不超过给定的整数 KK

输入格式

第一行包含三个整数 N,MN, MKK

之后 NN 行每行包含 MM 个整数, 代表矩阵 AA

输出格式

一个整数代表答案。

样例 #1

样例输入 #1

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

样例输出 #1

19

提示

【样例说明】

满足条件的子矩阵一共有 1919,包含:

大小为 1×11 \times 1 的有 1010 个。

大小为 1×21 \times 2 的有 33 个。 大小为 1×31 \times 3 的有 22 个。

大小为 1×41 \times 4 的有 11 个。

大小为 2×12 \times 1 的有 33 个。

【评测用例规模与约定】

对于 30%30 \% 的数据, N,M20N, M \leq 20.

对于 70%70 \% 的数据, N,M100N, M \leq 100.

对于 100%100 \% 的数据, 1N,M500,0Aij1000,1K2.5×1081 \leq N, M \leq 500,0 \leq A_{i j} \leq 1000,1 \leq K \leq 2.5\times10^8.

蓝桥杯 2022 省赛 B 组 F 题。

分析

说到这题真的是泪目了,第一次打蓝桥杯因为当时不会写二维前缀和,拿了个很丢人的省三(错失省二),痛定思痛,赛后就学习了二维前缀和,二位前缀和可以得70分,今天终于学会了满分做法(感谢y总),这题正解是用双指针加一维前缀和就ok啦,就是根据单调性,枚举行数,然后搞一下列的前缀和就ok了。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string> 
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack> 
#include <cmath>
#define ll long long
#define AC return
#define Please 0
using namespace std;
const int N=510;
const int N2=5;
typedef pair<int,int>PII;
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();
	}
	AC x*f;

}
int s[N][N];
int n,m,K; 
int tag[N+5][N+5];
int main(){
	cin>>n>>m>>K;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>s[i][j];
			s[i][j]+=s[i-1][j];
		}
	}
	ll res=0;
	ll sum;
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			for(int l=1,r=1,sum=0;r<=m;r++){
				sum+=s[j][r]-s[i-1][r];
				while(sum>K){
					sum-=s[j][l]-s[i-1][l];
					l++;
				}
				res+=r-l+1;
			}
		}
	}
	cout<<res<<endl;
	AC Please;
}

希望能帮助到大家(QAQQAQ)!