首先打表发现规律,如果L为奇数,那么行和列均以L为周期,若L为偶数,则均以2*L为周期。所以任何一个矩阵都可以拆解为若干个元矩阵+若干个部分元矩阵。
二维矩阵前缀和
对拍了半天没有找到不一样的地方但是就是WA……最开始WA在对S1234的处理上,如果直接调用getsum,那么当x0y0有一个是0的时候就会出现负数。数组越界。
改掉这一点之后还是WA了,还有另一个数组越界藏在一个不太好发现的地方,就是getsum函数的最后一个分支,一开始我没有细分为究竟是x小于周期还是y小于周期,这样就会导致y小于周期但是x可能很大,而我的sum数组只开了2000,对于1e8的数据规模就会发生数组越界。
不过这里修正之后就实在不知道哪里WA了……跑了半个多小时也没找到不一样的地方orz 问了超级强的队友以后,发现是对x0y0负数判断那里,注释掉给所有的调用统一+L(相当于把坐标面平移,以(L,L)为原点,可以巧妙的避免负数的问题,就像之前刷dp遇到平衡天平,从[-200,200]改为[0,400]一样)就可以AC了 ,不过这段码究竟有什么问题呢……玄学。
强大的队友找出了错。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_SIZE = 100000010;
int M[2000][2000], A[1000];
ll sum[2000][2000];
//int A[100] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int T, L, Q;
ll dx0, dy0, dx1, dy1, zhouqi;
ll ans, S1, S2, S3, S4;
ll getsum(ll x, ll y)
{
//printf("x = %lld y = %lld\n", x, y);
ll sumans = 0;
ll tx = x+1, ty = y+1;//不然直接/zhouqi结果不对
//printf("ans = %lld\n", sumans);
sumans = sum[zhouqi-1][zhouqi-1] * (tx/zhouqi) * (ty/zhouqi);
//printf("ans = %lld\n", sumans);
if(tx % zhouqi == 0 && ty % zhouqi == 0)
return sumans;
//printf("ans = %lld\n", sumans);
if(tx >= zhouqi && ty >= zhouqi)
{
if(tx%zhouqi == 0 || ty%zhouqi == 0)
{
if(ty%zhouqi == 0)
sumans = sumans + (ty/zhouqi)*sum[x%zhouqi][zhouqi-1];
else
sumans = sumans + (tx/zhouqi)*sum[zhouqi-1][y%zhouqi];
return sumans;
}
sumans = sumans + sum[x%zhouqi][y%zhouqi] + (y/zhouqi)*sum[x%zhouqi][zhouqi-1] + (x/zhouqi)*sum[zhouqi-1][y%zhouqi];
return sumans;
}
//printf("ans = %lld\n", sumans);
//有一维不满足情况
//sumans = sumans + sum[x%zhouqi][y%zhouqi] + (x/zhouqi)*sum[zhouqi-1][y] + (y/zhouqi)*sum[x][zhouqi-1];
sumans += sum[x%zhouqi][y%zhouqi];
//printf("ans = %lld\n", sumans);
if(ty < zhouqi)
sumans += (x/zhouqi)*sum[zhouqi-1][y];
//printf("ans = %lld\n", sumans);
if(tx < zhouqi)
sumans += (y/zhouqi)*sum[x][zhouqi-1];
//printf("ans = %lld\n", sumans);
return sumans;
}
int main()
{
scanf("%d", &T);
while(T--)
{
scanf("%d", &L);
for(int i = 0;i < L;i++)
{
scanf("%d", &A[i]);
}
if(L % 2 == 0)
zhouqi = 2*L;
else
zhouqi = L;
//printf("zhouqi = %d\n", zhouqi);
/**生成第一个矩阵**/
int cursor = 0;
for(int i = 0;i <= 400; ++i)
{
for(int j = 0; j <= i; ++j)
{
//printf("cursor = %d\n", cursor);
M[j][i - j] = A[cursor];
//printf("M[%d][%d] = A[%d] = %d\n", j, i-j, cursor, A[cursor]);
cursor = (cursor + 1) % L;
}
}
/*printf("\n");
for(int j = 0;j <= 30;j++)
{
for(int i = 0;i <= 30;i++)
{
printf("%03d ", M[j][i]);
}
printf("\n\n");
}
printf("\n");*/
/**前缀和预处理**/
//对每行第一个处理
for(int i = 0;i < zhouqi;i++)
sum[i][0] = M[i][0];
for(int i = 0;i < zhouqi;i++)//行
for(int j = 1;j < zhouqi;j++)//列
sum[i][j] = sum[i][j-1] + M[i][j];
//前面求出来的只是行前缀和
//下面对列进行处理
for(int i = 1;i < zhouqi;i++)//行
for(int j = 0;j < zhouqi;j++)//列
sum[i][j] += sum[i-1][j];
/**读入问题进行计算**/
scanf("%d", &Q);
for(int i = 1;i <= Q;i++)
{
scanf("%lld%lld%lld%lld", &dx0, &dy0, &dx1, &dy1);
/*if(dx0 == dx1 && dy0 == dy1)
{
ans = M[dx1%zhouqi][dy1%zhouqi];
printf("%lld\n", ans);
continue;
}*/
//printf("dx0 = %lld dy0 = %lld dx1 = %lld dy1 = %lld\n", dx0, dy0, dx1, dy1);
/*if(dx0 == 0 && dy0 == 0)
{
ans = getsum(dx1, dy1);
printf("%lld\n", ans);
continue;
}
else if(dx0 == 0)
{
ans = getsum(dx1, dy1) - getsum(dx1, dy0);
printf("%lld\n", ans);
continue;
}
else if(dy0 == 0)
{
ans = getsum(dx1, dy1) - getsum(dx0,dy1);
printf("%lld\n", ans);
continue;
}*/
//S = S1 - S3 - S4 + S2
//S1 = sum[x1][y1]
S1 = getsum(dx1 + L, dy1 + L);
//printf("S1 = %lld\n", S1);
//S2 = sum[x0-1][y0-1]
S2 = getsum(dx0 - 1 + L, dy0 - 1 + L);
//printf("S2 = %lld\n", S2);
//S3 = sum[x1][y0-1]
S3 = getsum(dx1 + L, dy0 - 1 + L);
//printf("S3 = %lld\n", S3);
//S4 = sum[x0-1][y1]
S4 = getsum(dx0 - 1 + L, dy1 + L);
//printf("S4 = %lld\n", S4);
ans = S1 - S3 - S4 + S2;
printf("%lld\n", ans);
}
}
return 0;
}