码迷,mamicode.com
首页 > 其他好文 > 详细

矩阵乘法2(codevs3147)

时间:2015-03-18 21:51:42      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:

题目描述 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<iostream>
#include<cstdio>
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);
       }
}

矩阵乘法2(codevs3147)

标签:

原文地址:http://blog.csdn.net/sunshinezff/article/details/44421845

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!