HDU6336 Matrix from Arrays

题意:有一个长度为L(1 <= L<= 10)的数组A和一个无限大的矩阵M。执行下面的代码:

int cursor = 0;

for (int i = 0; ; ++i) {
    for (int j = 0; j <= i; ++j) { 
        M[j][i - j] = A[cursor];
        cursor = (cursor + 1) % L;
    }
}

然后是Q次询问,每次输入两个点(x0,y0)(左上),(x1,y1)(右下),求子矩阵内的数字之和。

思路:可以看出M的填数顺序是这样的:

1 2 4 7 ...
3 5 8 ...  
6 9 ...    
10 ...      
...        

推导一番可得:

M[i, j] = A[((i + j) * (i + j + 1) / 2 + i) % L] = A[((i * i + j * j + i + j) / 2 + i * j + i) % L]

M[i + 2L, j] = A[((i + j + 2 * L) * (i + j + 1 + 2 * L) / 2 + i + 2 * L) % L] = A[((i * i + j * j + i + j) / 2 + i * j + i + 2 * (i + j + L + 1) * L) % L] = A[((i * i + j * j + i + j) / 2 + i * j + i) % L] = M[i, j]

同理,M[i, j + 2 * L] = M[i, j].

可以看出,整个矩阵都以2L* 2L 的小矩阵为循环节,打表求出循环节即可。

qk[i, j] 记录子矩阵[0, 0] 到 [i, j] 的元素之和。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <cstdlib>
#include <set>
#include <string>

using namespace std;

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 21;
int a[11], L;
ll qk[41][41];
ll calc(int n, int m) {
    if (n < 0 || m < 0) {
        return 0ll;
    }
    return qk[L - 1][L - 1] * (n / L) * (m / L)  // 被完整覆盖的小矩阵
    + qk[L - 1][m % L] * (n / L)                 // 右侧多余的小矩阵
    + qk[n % L][L - 1] * (m / L)                 // 下边多余的小矩阵
    + qk[n % L][m % L];                          // 右下角多余的部分
}
int main(){
    int t, q, x0, x1, y0, y1;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &L);
        for (int i = 0; i < L; ++i) {
            scanf("%d", &a[i]);
        }
        int k = 0;
        for (int i = 0; i < 4 * L; ++i) { //要求出完整的2L*2L的矩阵,i要循环到4L
            for (int j = 0; j <= i; ++j) {
                qk[j][i - j] = (ll)a[k];
                k = (k + 1) % L;
            }
        }
        L *= 2;
        for (int i = 0; i < L; ++i) { //二维前缀和
            for (int j = 0; j < L; ++j) {
                if (i) {
                    qk[i][j] += qk[i - 1][j];
                }
                if (j) {
                    qk[i][j] += qk[i][j - 1];
                }
                if (i && j) {
                    qk[i][j] -= qk[i - 1][j - 1]; //减去重复加的部分
                }
            }
        }
        scanf("%d", &q);
        while (q--) {
            scanf("%d%d%d%d", &x0, &y0, &x1, &y1);
            printf("%lld\n", calc(x1, y1) - calc(x1, y0 - 1) - calc(x0 - 1, y1) + calc(x0 - 1, y0 - 1)); //矩阵运算
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hcx11333/article/details/81336026