2016-06-01 17:33:30
题目链接: 矩阵乘法2 (Codevs No.3147)
题目大意:
给定两个大小相同的正方形矩阵A,B.多次询问,每次求乘后矩阵的一个子矩阵所有元素的和.
解法:
首先想到暴力.
预处理N^3,询问模拟扫,这常数简直瞬间爆炸啊
当然是可以优化的.
列出子矩阵的元素表达式,就会发现有一些元素//矩阵乘法2 (Codevs No.3147)
//矩阵乘法
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=2010;
int map1[maxn][maxn];
int map2[maxn][maxn];
long long ans;
int N,M;
int a,b,c,d;
int main()
{
scanf("%d %d",&N,&M);
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
scanf("%d",&map1[i][j]);
map1[i][j]+=map1[i-1][j];
}
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=N;j++)
{
scanf("%d",&map2[i][j]);
map2[i][j]+=map2[i][j-1];
}
}
for(int i=1;i<=M;i++)
{
ans=0;
scanf("%d %d %d %d",&a,&b,&c,&d);
for(int i=1;i<=N;i++)
{
int sumxmap2=map2[i][max(b,d)]-map2[i][min(b,d)-1];
int sumymap1=map1[max(a,c)][i]-map1[min(a,c)-1][i];
ans+=(long long)sumxmap2*sumymap1;
}
printf("%lld\n",ans);
}
return 0;
}的乘积可以做乘法分配律
所以直接放弃求出子矩阵的确切值,按照分配律的特点组合数据.
我们对A(乘法的时候乘行)进行列前缀和,对B(乘法的时候乘列)进行行前缀和
最后所有元素的和就可以表示成sigma((A[i][Dbound]-A[i][Ubound-1])*(B[i][Rbound]-B[i][Lbound-1]));
(Ubound,Dbound,Lbound,Rbound表示小矩阵的上下左右)
1 //矩阵乘法2 (Codevs No.3147) 2 //矩阵乘法 3 #include<stdio.h> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=2010; 7 int map1[maxn][maxn]; 8 int map2[maxn][maxn]; 9 long long ans; 10 int N,M; 11 int a,b,c,d; 12 int main() 13 { 14 scanf("%d %d",&N,&M); 15 for(int i=1;i<=N;i++) 16 { 17 for(int j=1;j<=N;j++) 18 { 19 scanf("%d",&map1[i][j]); 20 map1[i][j]+=map1[i-1][j]; 21 } 22 } 23 for(int i=1;i<=N;i++) 24 { 25 for(int j=1;j<=N;j++) 26 { 27 scanf("%d",&map2[i][j]); 28 map2[i][j]+=map2[i][j-1]; 29 } 30 } 31 for(int i=1;i<=M;i++) 32 { 33 ans=0; 34 scanf("%d %d %d %d",&a,&b,&c,&d); 35 for(int i=1;i<=N;i++) 36 { 37 int sumxmap2=map2[i][max(b,d)]-map2[i][min(b,d)-1]; 38 int sumymap1=map1[max(a,c)][i]-map1[min(a,c)-1][i]; 39 ans+=(long long)sumxmap2*sumymap1; 40 } 41 printf("%lld\n",ans); 42 } 43 return 0; 44 }