Day 4 E - Matrix from Arrays HDU 6336 | 打表找规律 | 二维矩阵前缀和

首先打表发现规律,如果L为奇数,那么行和列均以L为周期,若L为偶数,则均以2*L为周期。所以任何一个矩阵都可以拆解为若干个元矩阵+若干个部分元矩阵。
二维矩阵前缀和
分析一下可以发现任何(x0, y0) (x1, y1)构成的方形都可以拆解为这样四个部分对于(0, 0)(x, y)的求解 注意图上蓝色和橙色写反了
对拍了半天没有找到不一样的地方但是就是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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值