codevs#3147[题解]矩阵乘法2
2016-05-16 17:45
295 查看
题目描述 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。
数据有梯度。
80′暴力:
设第一个矩阵的第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,而且,虽然变量类型要用长整型,但是前缀和只能用整型,用长整型的只能是答案.
附代码:
ACcode:100scores.
给出两个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。
数据有梯度。
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; }
ACcode:100scores.
#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; }
相关文章推荐
- BZOJ 2759 一道动态树的好题
- Wireshark图解教程(统计)
- HTML table合并行列后,使用百分比设置列宽
- hbase Java API 介绍及使用示例
- eclipse从数据库逆向生成Hibernate实体类
- 平安好医生技术栈的分析
- Mac OS下PHP环境搭建及PHP操作MySQL常用方法小结
- Nullability、__covariant、__contravariant,__kindof
- android使用ant重新编译打包apk
- form表单中的值设置为disable后出现的问题
- Web服务的性能测试
- JazzyViewPager
- 五十四 网络编程 TCP编程
- Chrome保存mht网页文件的方法(无需插件)
- poj 2114 Boatherds
- Oracle函数
- Shiro--权限控制
- php 实现背景图上添加 圆形logo
- 数学系杀手(数学+找规律)(北理16校赛)
- pch文件添加