HDU 6336 Problem E. Matrix from Arrays

题意:

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.csdn.net/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);
        }
    }
}




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值