题目链接:hdu 6336 Problem E. Matrix from Arrays
Sample Input
1
3
1 10 100
5
3 3 3 3
2 3 3 3
2 3 5 8
5 1 10 10
9 99 999 1000
Sample Output
1
101
1068
2238
33076541
题意:给一个无限的矩阵,给出子矩阵左上角和右下角的坐标,求子矩阵中的数之和。
思路:首先看矩阵的构造,可以发现是这样构造的(图一)(图中数字表示第i个数字,以长度为4的数列为例),然后我们可以发现矩阵由2L*2L的子矩阵平铺构成(图二)(长度为5)
官方题解中是公式推导的:
其实通过打表,挺容易看出的,但是比赛期间,由于写法不对,所以代码比较麻烦,一直没有对。较为便利的方法是,通过求2L*2L单位矩阵的二维前缀和(就是从(0,0)到(i,j)这样的矩阵的和),就可以快速求得答案。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
ll a[50];
ll map[50][50];
int L;
void init(){
memset(map,0,sizeof map);
int cursor=0;
for (int i = 0;i<L*4; ++i) {
for (int j = 0; j <= i; ++j) {
map[j][i-j] = a[cursor];
cursor=(cursor+1)%(L);
}
}
for(int i=0;i<2*L;i++){
for(int j=0;j<2*L;j++){
if((i>0)&&(j>0))map[i][j]+=map[i-1][j]+map[i][j-1]-map[i-1][j-1];
if((i>0)&&(j==0))map[i][j]+=map[i-1][j];
if((i==0)&&(j>0))map[i][j]+=map[i][j-1];
}
}
}
ll f(int x,int y){
if(x<0||y<0)return 0;
ll ans=0;
ll xx=x/L;//这里不用long long就会wa
ll yy=y/L;
ll sx=x%L;
ll sy=y%L;
ans+=xx*yy*map[L-1][L-1];
ans+=yy*map[sx][L-1];
ans+=xx*map[L-1][sy];
ans+=map[sx][sy];
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&L);
for(int i=0;i<L;i++){
scanf("%lld",&a[i]);
}
init();
int q;
scanf("%d",&q);
L=L*2;
while(q--){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%lld\n",f(x2,y2)-f(x2,y1-1)-f(x1-1,y2)+f(x1-1,y1-1));
}
}
return 0;
}