计蒜客-T1320-子矩阵求和

题目链接:https://nanti.jisuanke.com/t/T1320

题目描述

给出一个 nn 行 mm 列的矩阵,矩阵的每个位置有一个非负整数 a[i][j]a[i][j],有 qq 次询问,每次询问求一个左上角为 (a,b)(a,b),右下角为 (c,d)(c,d) 的子矩阵的所有数之和。

输入格式

第一行两个整数 n,m,表示矩阵的行和列的大小。

接下来 n 行每行 m 个整数,为矩阵内容。

接下来一行为一个整数 q ,表示询问次数。

接下来 q 行每行 4 个整数 a,b,c,d,含义见题面。

输出格式

共 q 行,第 i 行为第 ii个询问的答案。

数据范围

n×m≤100,000,a[i][j] \le 1000a[i][j]≤1000,q \le 100,000q≤100,000,1 \le a \le c \le n1≤a≤c≤n,1 \le b \le d \le m1≤b≤d≤m。

输出时每行末尾的多余空格,不影响答案正确性

输出时每行末尾的多余空格,不影响答案正确性

样例输入

3 5
1 2 3 4 5
3 2 1 4 7
2 4 2 1 2
3
1 1 3 5
2 2 3 3
1 1 3 3

样例输出

43
9
20

题目分析:

1.这题很容易理解,就是求一个矩阵所有元素的和,但是如果用二维数组求解的话会出问题,因为n×m≤100,000,可能是1*100000,也可能是100000*1,如果定义一个100000*100000的数组又不现实(开不到这么大的数组),所以可以把二维数组存到一位数组里面。当然用vector的话,二维数组也可以采用。

2.下面先看一下用二维数组怎么实现这一题(一维数组和二维数组类似,但是没有二维数组好理解,先用二维数组讲解)

3.最后带上vector的代码

二维代码思路:

如图所示,假设要求S的话,可以用最大的矩形和减去S1+S2,再减去S1+S3,最后再加上S1即可。

二维数组代码:

#include<iostream>
#include<vector>
using namespace std;
int n,m;
int s[1000][1000],dp[1000][1000];
int main()
{
	int i,j,q,a,b,c,d;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			cin>>s[i][j]; 
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+s[i][j];
	cin>>q;
	while(q--)
	{
		cin>>a>>b>>c>>d;
		cout<<dp[c][d]+dp[a-1][b-1]-dp[a-1][c]-dp[c][b-1]<<endl;
	}
	return 0;
}

一维数组代码:

#include<iostream>
using namespace std;
int s[200001];
int main()
{
	int n,m,i,j,t,q,a,b,c,d;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			scanf("%d",&t);
			s[i*m+j]=s[(i-1)*m+j]+s[i*m+j-1]-s[(i-1)*m+j-1]+t;
		}
	}
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d%d%d%d",&a,&b,&c,&d);
		printf("%d\n",s[c*m+d]+s[(a-1)*m+b-1]-s[(a-1)*m+d]-s[c*m+b-1]);
	}
	return 0;
}

一维数组思路:

一维数组和二维数组类似,具体可以看代码。

需要注意的地方:

输入输出要用 scanf 和 printf ,不然会超时。

vector二维数组代码:

#include<iostream>
#include<vector>
using namespace std;
int n,m;
vector<vector<int> > s,dp;
vector<int> k1,k2;
int main()
{
	int i,j,q,a,b,c,d,t;
	cin>>n>>m;
	for(i=0;i<m;i++)
	{
		k1.push_back(0);
	}
	s.push_back(k1);
	dp.push_back(k1);
	for(i=1;i<=n;i++)
	{
		k1.clear();
		k2.clear();
		k1.push_back(0);//这是为了把输入的数从下标1开始,这样方便计算
		k2.push_back(0);
		for(j=1;j<=m;j++)
		{
			cin>>t;
			k1.push_back(t);
			k2.push_back(0);
		}
		s.push_back(k1);
		dp.push_back(k2);
	}
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+s[i][j];
	cin>>q;
	while(q--)
	{
		scanf("%d%d%d%d",&a,&b,&c,&d);
		printf("%d\n",dp[c][d]+dp[a-1][b-1]-dp[a-1][d]-dp[c][b-1]);
	}
	return 0;
}

 

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值