向前走莫回头❤

【codevs 3147】矩阵乘法 2 2012年(乱搞)

3147 矩阵乘法 2 2012年
时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master
题目描述 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
【数据规模和约定】
对40%的数据满足,n <= 100,m <= 1000。
对100%的数据满足,n <= 800,m <= 10000,输入数据中矩阵元素 < 100,a,b,c,d <= n。
数据有梯度。

【这道题很坑人,我刚开始乖乖地写矩乘,然而由于单纯的矩阵乘法就已经是O(n^3)了,所以再加上O(n^2)的查询就T了;后来做完矩乘后维护整个矩阵的前缀和,将查询操作压至O(n),然而还是T】
【这道题其实不是一个矩阵乘法,可以通过公式推一下】
【通过推公式可以看出,这道题只需先计算出a、b两个数组的前缀和(a数组求每一列的前缀和;b数组求每一行的前缀和),最后在循环m时,用前缀和相减,求出区间内的和,并相乘,这样就能将计算子矩阵的和的时间压至O(n),核心程序段的复杂度为O(nm),就可以过了。】
【注意:小心MLE】

i=x1x2j=y1y2Ci,j

=i=x1x2j=y1y2k=1na[i][k]×b[k][j]

=k=1ni=x1x2a[i][k]j=y1y2b[k][j]

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[2001][2001],b[2001][2001];
int n,m,x1,y1,x2,y2;
int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;++i)
     for (j=1;j<=n;++j)
        {
          scanf("%d",&a[i][j]);
          a[i][j]+=a[i-1][j];    
        }
    for (i=1;i<=n;++i)
     for (j=1;j<=n;++j)
      {
        scanf("%d",&b[i][j]);
        b[i][j]+=b[i][j-1];
      }
   for (i=1;i<=m;++i)
    {
      scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
      long long s1,s2; 
      long long ans=0;
      for (j=1;j<=n;j++)
        {
            s1=a[max(x1,x2)][j]-a[min(x1,x2)-1][j];
            s2=b[j][max(y1,y2)]-b[j][min(y1,y2)-1];
            ans=ans+s1*s2;
        }
      printf("%lld\n",ans); 
    }
   return 0;      
} 
posted @ 2016-11-15 11:25  lris0-0  阅读(84)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m