题意:
给你一个n,然后输入a[n]数组,按照题目构建一个矩阵,有q个查询,每一个查询有x0,y0,x1,y1,求该矩阵区间的和。
题解:
打表可以发现矩阵是由长度2*n(奇数是n)的小矩阵构成。
由图得:ans = S(x1,y1) - S(x0-1,y1) - S(x1,y0-1) + S(x0,y0)。
设小矩阵的和为 S, 小矩阵的每一行的和为Si,小矩阵的每一列的和为Sj:
则S(x,y) =(x/n)*(y/n)*S + Si(0 -> (x%n)) + Sj(0 -> (y%n)) + mapp[i][j](0 -> (x%n), 0 -> (y%n))。
代码如下:
#include <bits/stdc++.h>
#define ll long long
#define mem(a) memset(a, 0, sizeof(a))
using namespace std;
ll mapp[105][105];
ll a[15];
ll sum_i[105], sum_j[105], sum;
ll n;
void init(){
int cnt = 0;
for(int i = 0; i < 4*n; i++){
for(int j = 0; j <= i; j++){
mapp[j][i-j] = a[cnt];
cnt = (cnt+1)%n;
}
}
sum = 0;
mem(sum_i);
mem(sum_j);
for(int i = 0; i < 2*n; i++){
for(int j = 0; j < 2*n; j++){
sum += mapp[i][j];
sum_i[i] += mapp[i][j];
sum_j[j] += mapp[i][j];
}
}
}
ll getSum(int x, int y){
ll temp = 0;
int x1 = (x+1)/(2*n), y1 = (y+1)/(2*n);
x = (x+1) % (2*n), y = (y+1) % (2*n);
temp = sum * x1 * y1;
for(int i = 0; i < y; i++){
temp += x1*sum_j[i];
}
for(int i = 0; i < x; i++){
temp += y1*sum_i[i];
}
for(int i = 0; i < x; i++){
for(int j = 0; j < y; j++){
temp += mapp[i][j];
}
}
return temp;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%lld", &n);
for(int i = 0; i < n; i++){
scanf("%lld", &a[i]);
}
init();
int q;
scanf("%d", &q);
while(q--){
int x0, y0, x1, y1;
scanf("%d %d %d %d", &x0, &y0, &x1, &y1);
printf("%lld\n", getSum(x1, y1) - getSum(x1, y0-1) - getSum(x0-1, y1) + getSum(x0-1, y0-1));
}
}
}