给出两个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
【数据规模和约定】
对40%的数据满足,n <= 100,m <= 1000。
对100%的数据满足,n <= 800,m <= 10000,输入数据中矩阵元素 < 100,a,b,
c,d <= n。
数据有梯度。
80′暴力:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; struct Mart { int a[801][801]; }A,B,C; void Martix(Mart A,Mart B) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { for(int k=1;k<=n;k++) { C.a[i][j]+=A.a[i][k]*B.a[k][j]; } // printf("%d ",C.a[i][j]); } //printf("\n"); } } int x1,x2,y1,y2; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&A.a[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&B.a[i][j]); Martix(A,B); for(int k=1;k<=m;k++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); long long ans = 0; if(x1>x2)swap(x1,x2); if(y1>y2)swap(y1,y2); for(int i=x1;i<=x2;i++) { for(int j=y1;j<=y2;j++) { ans += C.a[i][j]; } } printf("%lld\n",ans); } return 0; }
设第一个矩阵的第i行第j列为a[i][j],第二个为b[i][j],根据矩阵乘法的定义,答案为∑(min(a,c)<=i<=max(a,c),min(b,d)<=j<=max(b,d))(∑(1<k<n)a[i][k]*b[k][j]),
时间复杂度为O(n^3),会超时.
所以我们必须将其变形:
加法结合律,得:∑(1<k<n)(∑(min(a,c)<=i<=max(a,c))(∑(min(b,d)<=j<=max(b,d))(a[i][k]*b[k][j]))),
乘法结合侓,得:∑(1<k<n)((∑(min(a,c)<=i<=max(a,c))a[i][k])*(∑(min(b,d)<=j<=max(b,d))b[k][j])),
时间复杂度为降至O(n^2),但由于要计算m次,还是会超时.
但我们可以发现,∑(min(a,c)<=i<=max(a,c))a[i][k]和∑(min(b,d)<=j<=max(b,d))b[k][j]可以用前缀和来求,
于是时间复杂度再降至O(n),但要额外加上与处理的O(n^2),
所以总时间复杂度为O(mn+n^2).
注意:由于空间限制是64000KB,所以,获得前缀和后不能保留矩阵a和矩阵b,而且,虽然变量类型要用长整型,但是前缀和只能用整型,用长整型的只能是答案.
附代码:
#include<iostream> using namespace std; int n,m,i,j,matrix1[2001][2001]={},matrix2[2001][2001]={},a,b,c,d; long long answer; int main () { cin>>n>>m; for (i=1;i<=n;i++) for (j=1;j<=n;j++) scanf("%d",&matrix1[i][j]); for (i=1;i<=n;i++) for (j=1;j<=n;j++) scanf("%d",&matrix2[i][j]); for (i=1;i<=n;i++) for (j=1;j<=n;j++) matrix1[i][j]+=matrix1[i-1][j]; for (i=1;i<=n;i++) for (j=1;j<=n;j++) matrix2[i][j]+=matrix2[i][j-1]; for (i=1;i<=m;i++) { scanf("%d %d %d %d",&a,&b,&c,&d); answer=0; for (j=1;j<=n;j++) answer+=(long long)(matrix1[max(a,c)][j]-matrix1[min(a,c)-1][j])*(long long)(matrix2[j][max(b,d)]-matrix2[j][min(b,d)-1]); cout<<answer<<endl; } return 0; }
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m; struct Mart { int a[801][801]; }A,B; int x1,x2,y1,y2; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&A.a[i][j]); A.a[i][j]+=A.a[i-1][j]; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&B.a[i][j]); B.a[i][j]+=B.a[i][j-1]; } for(int k=1;k<=m;k++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); long long ans = 0; if(x1>x2)swap(x1,x2); if(y1>y2)swap(y1,y2); for(int j=1;j<=n;j++) ans+=(A.a[x2][j]-A.a[x1-1][j])*(B.a[j][y2]-B.a[j][y1-1]); printf("%lld\n",ans); } return 0; }