题目描写叙述 Description
给出两个n*n的矩阵。m次询问它们的积中给定子矩阵的数值和。输入描写叙述 Input Description
第一行两个正整数n,m。接下来n行,每行n个非负整数。表示第一个矩阵。 接下来n行,每行n个非负整数。表示第二个矩阵。 接下来m行。每行四个正整数a。b,c,d,表示询问第一个矩阵与第二个矩阵的积中。 以第a行第b列与第c行第d列为顶点的子矩阵中的元素和。
输出描写叙述 Output Description
对每次询问,输出一行一个整数。表示该次询问的答案。 例子输入 Sample Input 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例子输出 Sample Output
661 388 数据范围及提示 Data Size & Hint 【数据规模和约定】对30%的数据满足,n <= 100。
对100%的数据满足。n <= 2000,m <= 50000,输入数据中矩阵元素 < 100,a。b。 c,d <= n。题解: 这个题尽管名字是矩阵乘法。可是和矩阵高速幂一点关系也没有。。
30%做法: 直接两个矩阵暴力相乘,然后再暴力询问。(ps:集训队的题居然给这么多暴力分) 100%做法: 如果你对矩阵乘法足够了解的话。能够发现我们事实上能够在O(n)的复杂度内处理出每次询问。 设要求和的矩阵为A(x1,x2,y1,y2);第一个矩阵为a,第二个矩阵为b那么矩阵A能够分行来计算 如果A矩阵第一行(x1)的元素为p[i]; 那么依据矩阵乘法的法则 p[i]等于a矩阵的第X1行的元素和b矩阵的第i列的元素相应相乘。再相加。
sigma{p[i]}(y1<=i<=y2)为a矩阵的第X1行的元素分别和b矩阵的第y1到y2列的元素相应相乘,再相加。 那么我们能够发现这个式子能够使用乘法结合律提出a矩阵第x1行的元素。再用第i个元素与b矩阵第i列的和相乘,最后把所得的乘积相加, 同理第二行第三行也都一样, 我们会发现不同行之间也能够提取出b矩阵中每一列的和, 那么最后所询问矩阵的和就为a矩阵第x1-x2行每行的元素和与b矩阵第y1-y2列的每列的元素和相应相乘再相加。 所以仅仅要预处理出a矩阵每一行的前缀和 b矩阵每一列的前缀和就可以 时间复杂度O(n^2+n*m); 注意使用scanf或读入优化。 代码:
#include#include using namespace std;#define For(i,n) for(int i=1;i<=n;i++) #define read(x) scanf("%d",&x); int n,m,x,y,xx,yy,aa[2001][2001]={0},bb[2001][2001]={0},a,b;int main(){ read(n);read(m); For(i,n) For(j,n) { read(a); aa[i][j]=aa[i-1][j]+a; } For(i,n) For(j,n) { read(b); bb[i][j]=bb[i][j-1]+b; } For(i,m) { read(x);read(y);read(xx);read(yy); long long ans=0; if (x>xx) swap(x,xx); if (y>yy) swap(y,yy); For(j,n) ans+=(long long)(aa[xx][j]-aa[x-1][j])*(long long)(bb[j][yy]-bb[j][y-1]); printf("%lld\n",ans); }}