codevs3147 矩阵乘法 2 (推导小公式)

2017年04月14日 15点热度 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

【数据规模和约定】

对40%的数据满足,n <= 100,m <= 1000。
对100%的数据满足,n <= 800,m <= 10000,输入数据中矩阵元素 < 100,a,b,
c,d <= n。

数据有梯度。

//事实证明,读取long long比int费时
//读long long 过两组,读int过4组
//想要过5组就要推导公式,把原来的时间复杂度n^3变成n*n+n*m,公式画个图即可推出 
#include
#include
using namespace std;
const int mx=810;
long long cc[mx][mx],dd[mx][mx];
inline int read(){
	int t=getchar(),ans=0;
	while(t<'0'||t>'9') t=getchar();
	while(t>='0'&&t<='9'){
		ans=ans*10+t-'0';
		t=getchar();
	}
	return ans;
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		cc[i][j]=cc[i-1][j]+read();
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
		dd[i][j]=dd[i][j-1]+read();
	int t1,t2,t3,t4;
	for(int i=1;i<=m;i++){
		long long tt,ttt,ans=0;
		tt=ttt=0;
		t1=read(),t2=read(),t3=read(),t4=read();
		if(t1>t3) swap(t1,t3);//转化为左上角和右下角 
		if(t2>t4) swap(t2,t4);
		for(int i=1;i<=n;i++)
		{
			ans+=(cc[t3][i]-cc[t1-1][i])*(dd[i][t4]-dd[i][t2-1]);
		}
		printf("%lldn",ans);
	}
	return 0;
}
未经允许不得转载!codevs3147 矩阵乘法 2 (推导小公式)

update

纸上得来终觉浅, 绝知此事须躬行。