题意:
for (int i = 0; ; ++i) { for (int j = 0; j <= i; ++j) { M[j][i - j] = A[cursor]; cursor = (cursor + 1) % L; } }
按照题目中给的上述方法可以构造出一个无限矩阵
问给你两个坐标,分别是子矩阵的左上角和左下角,让你求这个子矩阵的元素和
(0≤x0≤x1≤10^8,0≤y0≤y1≤10^8)
思路: 借鉴https://blog.youkuaiyun.com/sirius_han/article/details/81353413
打表,可以发现当L为奇数时,这个无限矩阵是以L*L这个子矩阵平铺的(循环),当L为偶数时,是一个2L*2L的循环矩阵
那么统一把循环节设为2L即可;先打表构造出循环矩阵,求前缀和sum[i][j]
(图一) (图二)
(图三)
如图一:以3*3的循环矩阵为例,紫色矩阵是目标矩阵,可以转化成图二,根据容斥原理S=S1-S2-S3+S4;;S1, S2, S3, S4都是以(x, y)为右下角,以(0, 0)为左上角的矩阵,问题就转化成了求这样的矩阵图三;米黄色的面积表示有多少个完整的循环矩阵,下方白条及右方白条表示只有长或宽不完整的矩阵,橙黄色面积表示不完整的循环矩阵;
#include <cstdio>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <iostream>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N = 120; //¸´ÔÓ¶ÈO(n)
ll sum[N][N],a[N],m[N][N];
int len;
ll Sum(ll x,ll y)
{
ll ans=(x/len)*(y/len)*sum[len][len];
ans+=(y/len)*sum[x%len][len]+(x/len)*sum[len][y%len];
ans+=sum[x%len][y%len];
return ans;
}
int main()
{
int t,i,j,q,n,cursor;
ll ans,x1,x2,y1,y2;
scanf("%d",&t);
while(t--)
{
cursor=0;
scanf("%d",&n);
len=2*n;
for(i=0;i<n;i++) scanf("%lld",&a[i]);
for(i=0;i<=100;i++)
{
for(j=0;j<=i;j++)
{
m[j+1][i-j+1]=a[cursor];
cursor=(cursor+1)%n;
}
}
for(i=1;i<=len;i++)
for(j=1;j<=len;j++)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+m[i][j];
scanf("%d",&q);
while(q--)
{
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
x1++;y1++;x2++;y2++;
ans=Sum(x2,y2)-Sum(x2,y1-1)-Sum(x1-1,y2)+Sum(x1-1,y1-1);
printf("%lld\n",ans);
}
}
}