Problem E. Matrix from Arrays
题意:按照题目方法构造一个矩阵,给出左上角和右下角的坐标问以两点连线为对角线的矩阵的和;
思路:打表发现,当L是奇数时,构造的矩阵是一个L*L的循环矩阵;L是偶数时,构造的矩阵是一个2L*2L的循环矩阵;那么统一把循环节设为2L即可;先打表构造出循环矩阵,求前缀和sum[i][j];最好让矩阵的x, y都从1开始;将题目给出的稍微修改一下就可以了;
(图一) (图二)
(图三)
如图一:以3*3的循环矩阵为例,紫色矩阵是目标矩阵,可以转化成图二,根据容斥原理S=S1-S2-S3+S4;;S1, S2, S3, S4都是以(x, y)为右下角,以(0, 0)为左上角的矩阵,问题就转化成了求这样的矩阵图三;米黄色的面积表示有多少个完整的循环矩阵,下方白条及右方白条表示只有长或宽不完整的矩阵,橙黄色面积表示不完整的循环矩阵;
注意要用long long;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll len, M[110][110], sum[25][25], a[20];
ll Sum(ll x, ll y){
ll ans=(x/len)*(y/len)*sum[len][len];//求米黄色部分和;
ans+=sum[x%len][len]*(y/len)+sum[len][y%len]*(x/len);//求白条部分和
ans+=sum[x%len][y%len];//求橙黄色部分和;
return ans;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
ll L;
scanf("%lld", &L);
for(ll i=0; i<L; i++){
scanf("%lld", &a[i]);
}
ll cnt=0;
for(ll i=0; i<=100; i++){
for(ll j=0; j<=i; j++){
M[j+1][i-j+1]=a[cnt];
cnt=(cnt+1)%L;
}
}
len=2*L;
memset(sum, 0, sizeof(sum));
for(ll i=1LL; i<=len; i++){
for(ll j=1LL; j<=len; j++){
sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+M[i][j];
}
}
int Q;
scanf("%d", &Q);
while(Q--){
ll x0, x1, y0, y1;
scanf("%lld%lld%lld%lld", &x0, &y0, &x1, &y1);
x0++, x1++, y0++, y1++;
ll ans=Sum(x1, y1)-Sum(x1, y0-1)-Sum(x0-1, y1)+Sum(x0-1, y0-1);//S=S1-S2-S3+S4;
printf("%lld\n", ans);
}
}
return 0;
}