首页 > 代码库 > 【bzoj2901】矩阵求和 前缀和

【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
2 3 1 2

样例输出

661
388


题解

前缀和

不妨设a<=c,b<=d,那么$\ \ \ \sum\limits_{i=a}^c\sum\limits_{j=b}^dR[i][j]\\=\sum\limits_{i=a}^c\sum\limits_{j=b}^d\sum\limits_{k=1}^nP[i][k]·Q[k][j]\\=\sum\limits_{k=1}^n(\sum\limits_{i=a}^cP[i][k])·(\sum\limits_{j=b}^dQ[k][j])\\=\sum\limits_{k=1}^n(sumP[c][k]-sumP[a-1][k])(sumQ[k][d]-sumQ[k][b-1])$

时间复杂度$O(nm)$,可过。

#include <cstdio>#include <algorithm>using namespace std;#define N 2010int p[N][N] , q[N][N] , sp[N][N] , sq[N][N];inline int read(){	int ret = 0; char ch = getchar();	while(ch < ‘0‘ || ch > ‘9‘) ch = getchar();	while(ch >= ‘0‘ && ch <= ‘9‘) ret = (ret << 3) + (ret << 1) + ch - ‘0‘ , ch = getchar();	return ret;}int main(){	int n , m , i , j , a , b , c , d;	long long ans;	n = read() , m = read();	for(i = 1 ; i <= n ; i ++ )		for(j = 1 ; j <= n ; j ++ )			a = read() , sp[i][j] = sp[i - 1][j] + a;	for(i = 1 ; i <= n ; i ++ )		for(j = 1 ; j <= n ; j ++ )			a = read() , sq[i][j] = sq[i][j - 1] + a;	while(m -- )	{		a = read() , b = read() , c = read() , d = read();		if(a > c) swap(a , c);		if(b > d) swap(b , d);		ans = 0;		for(i = 1 ; i <= n ; i ++ ) ans += (long long)(sp[c][i] - sp[a - 1][i]) * (sq[i][d] - sq[i][b - 1]);		printf("%lld\n" , ans);	}	return 0;}

 

 

【bzoj2901】矩阵求和 前缀和