矩阵求和


矩阵求和


难度级别:A; 编程语言:不限;运行时间限制:3000ms; 运行空间限制:256000KB; 代码长度限制:2000000B


试题描述


矩阵求和


输入


第一行n和m,表示行数和列数
接下来n行表示矩阵
再来一行一个整数q,表示询问个数
接下来q行,每行四个整数x1,y1,x2,y2表示左上右下的坐标


输出


对于每个询问输出一个整数表示该矩阵范围内的整数和


输入示例


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


输出示例


45
103
52


其他说明


n,m < 2001
q < 100001
矩阵内所有数小于2000

代码:

 1 #include<iostream>
 2
 3 int a,m,n,i,j,k,x1,y1,x2,y2;
 4
 5 long long sum,s[2002][2002]={0};//数组s用来储存前缀和
 6
 7 using namespace std;
 8
 9 int main()
10
11 {
12
13             scanf("%d%d",&m,&n);
14
15 for(i=1;i<=m;i++)//输入,赋值二维数组s
16
17                 for(j=1;j<=n;j++)
18
19                 {
20
21                      scanf("%d",&a);//为了节省空间,以单个变量输入
22
23                      s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
24
25                 }
26
27             scanf("%d",&k);
28
29             while(k--)
30
31             {
32
33                  scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
34
35                  sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
36
37                  printf("%lld\n",sum);
38
39             }
40
41 }

代码分析:

有三种方法:

1.    直接求解,按单个元素记录。因此,k次查询里每次都要有两个循环,一个横着在这个区间里扫描,另一个竖着扫描。

代码如下:

 1 #include<iostream>
 2
 3 int a[2010][2010],m,n,i,j,k,b,c,d,e;
 4
 5 long long sum;
 6
 7 using namespace std;
 8
 9 int main()
10
11 {
12
13     scanf("%d%d",&m,&n);
14
15     for(i=1;i<=m;i++)
16
17     {
18
19         for(j=1;j<=n;j++)
20
21         scanf("%d",&a[i][j]);
22
23     }
24
25     cin>>k;
26
27     while(k--)
28
29     {
30
31         sum=0;
32
33         scanf("%d%d%d%d",&b,&c,&d,&e);
34
35         for(i=b;i<=d;i++)//两次循环
36
37             for(j=c;j<=e;j++)
38
39                 sum+=a[i][j];
40
41         printf("%lld\n",sum);
42
43
44
45     }
46
47 }

这个方法显然效率太低,两次循环太耗费时间了,所以要考虑运用前缀和的办法了。

2.    利用之前数组储存前缀和的办法,给这个二维数组每行都求一个前缀和,然后在查询时,用要求的区间当中每一行的从y1到y2的和,用s[x][y2]-s[x][y1-1](x为第x行)

所以采用这个方法效率比上一个方法更快。

代码:

 1 #include<iostream>
 2
 3 int a,m,n,i,j,k,b,c,d,e,s[2002][2002]={0};
 4
 5 long long sum;
 6
 7 int main()
 8
 9 {
10
11     scanf("%d%d",&m,&n);
12
13     for(i=1;i<=m;i++)
14
15         for(j=1;j<=n;j++)
16
17         {
18
19             scanf("%d",&a);
20
21             s[i][j]=s[i][j-1]+a;
22
23         }
24
25     scanf("%d",&k);
26
27     while(k--)
28
29     {
30
31         sum=0;
32
33         scanf("%d%d%d%d",&b,&c,&d,&e);
34
35         for(i=b;i<=d;i++)
36
37             sum+=(s[i][e]-s[i][c-1]);
38
39         printf("%lld\n",sum);
40
41     }
42
43 }

这个方法不用两次循环,可还是有一次循环,但这还不能令人满意,有没有更快的方法呢?

分析上两个方法,我们发现:

这是第一个方法,它是以单个元素来求解的(以点做前缀和的)。一步步来累加。

第二个方法,前缀和,相当于是以行做单位求解。

既然,以行做前缀和的有了,    以点做前缀和的有了,那能不能以面做前缀和呢?

分析如下:

如此,推算赋值公式就如韦恩图那样:

 

把s[i-1][j]和s[i][j-1]加起来,s[i-1][j-1]部分重叠了,所以要减去,在加上输入的a,就得到:

s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;

而输出就也像上面一样,s[x2][y2]是从坐标(11)开始的,所以要减去s[x2][y1-1]s[x1-1][y2],s[x1-1][y1-1]被多减了,所以要加上。

代码:

 1 #include<iostream>
 2
 3 long long sum,a,m,n,i,j,k,x1,y1,x2,y2,s[2002][2002]={0};
 4
 5 using namespace std;
 6
 7 int main()
 8
 9 {
10
11     scanf("%d%d",&m,&n);
12
13     for(i=1;i<=m;i++)
14
15         for(j=1;j<=n;j++)
16
17         {
18
19             scanf("%d",&a);
20
21             s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
22
23         }
24
25     scanf("%d",&k);
26
27     while(k--)
28
29     {
30
31         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
32
33         sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
34
35         printf("%lld\n",sum);
36
37     }
38
39 }

这个方法只用一次运算便求出了解,所以它是三个方法中最快的方法。

时间: 2024-12-29 09:09:14

矩阵求和的相关文章

矩阵求和--重载运算符

C++习题 矩阵求和--重载运算符 [Submit][Status][Web Board] Description 有两个矩阵a和b,均为2行3列.求两个矩阵之和.重载运算符"+",使之能用于矩阵相加(如c=a+b). 重载流插入运算符"<<"和流提取运算符">>",使之能用于该矩阵的输入和输出. Input 两个2行3列矩阵 Output 矩阵之和 Sample Input 1 2 34 5 67 8 91 2 3 Sa

poj 3233 Matrix Power Series(等比矩阵求和)

http://poj.org/problem?id=3233 ps转: 用二分方法求等比数列前n项和:即 原理: (1)若n==0 (2)若n%2==0     (3)若n%2==1 代码如下: LL sum(LL p,LL n) { if(n==0) return 1; if(n&1) return (1+pow(p,(n>>1)+1))*sum(p,n>>1); else return (1+pow(p,(n>>1)+1))*sum(p,(n-1)>&

poj 1195:Mobile phones(二维树状数组,矩阵求和)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

poj 1195:Mobile phones(二维线段树,矩阵求和,经典题)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14391   Accepted: 6685 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

hdu 1588(Fibonacci矩阵求和)

题目的大意就是求等差数列对应的Fibonacci数值的和,容易知道Fibonacci对应的矩阵为[1,1,1,0],因为题目中f[0]=0,f[1]=1,所以推出最后结果f[n]=(A^n-1).a,所以 f(g(i))= f(k*i+b)= (A^(k*i+b-1)).a,i从 0取到 n-1,取出公因式 A^(b-1)(因为矩阵满足分配率),然后所求结果可化为 A^(b-1) * (A^0 + A^k + A^2k +....+ A^(n-1)k),化到这里后难点就是求和了,一开始我尝试暴力

【BZOJ2901】矩阵求和 临时版

Description 给出两个n*n的矩阵,m次询问它们的积中给定子矩阵的数值和. Input 第一行两个正整数n,m. 接下来n行,每行n个非负整数,表示第一个矩阵. 接下来n行,每行n个非负整数,表示第二个矩阵. 接下来m行,每行四个正整数a,b,c,d,表示询问第一个矩阵与第二个矩阵的积中,以第a行第b列与第c行第d列为顶点的子矩阵中的元素和. Output 对每次询问,输出一行一个整数,表示该次询问的答案. Sample Input 3 2 1 9 8 3 2 0 1 8 3 9 8

第十五周oj刷题——Problem M: C++习题 矩阵求和--重载运算符

Description 有两个矩阵a和b,均为2行3列.求两个矩阵之和.重载运算符"+",使之能用于矩阵相加(如c=a+b). 重载流插入运算符"<<"和流提取运算符">>".使之能用于该矩阵的输入和输出. Input 两个2行3列矩阵 Output 矩阵之和 Sample Input 1 2 3 4 5 6 7 8 9 1 2 3 Sample Output 8 10 12 5 7 9 /* All rights res

【bzoj2901】矩阵求和 前缀和

题目描述 给出两个n*n的矩阵,m次询问它们的积中给定子矩阵的数值和. 输入 第一行两个正整数n,m. 接下来n行,每行n个非负整数,表示第一个矩阵. 接下来n行,每行n个非负整数,表示第二个矩阵. 接下来m行,每行四个正整数a,b,c,d,表示询问第一个矩阵与第二个矩阵的积中,以第a行第b列与第c行第d列为顶点的子矩阵中的元素和. 输出 对每次询问,输出一行一个整数,表示该次询问的答案. 样例输入 3 2 1 9 8 3 2 0 1 8 3 9 8 4 0 5 15 1 9 6 1 1 3 3

矩阵求和及Kadane算法

今天的一道题目: https://leetcode.com/problems/max-sum-of-sub-matrix-no-larger-than-k/ 有难度.这一类题目很有代表性. 搜到这个网址有针对一维数组的求和的按照时间复杂度一步步优化的过程,讲的很不错: http://www.cnblogs.com/en-heng/p/3970231.html 然后针对题目中所提到的需要限制最大和不超过k的方式,也有方法通过set集合以及lower_bound或者upper_bound来处理, 整