Problem E. Matrix from Arrays

Problem E. Matrix from Arrays

Problem Description

Kazari has an array A length of L , she plans to generate an infinite matrix M using A .
The procedure is given below in C/C++:

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; 
       }
}

Her friends don’t believe that she has the ability to generate such a huge matrix, so they come up with a lot of queries about M , each of which focus the sum over some sub matrix. Kazari hates to spend time on these boring queries. She asks you, an excellent coder, to help her solve these queries.

Input

The first line of the input contains an integer T (1T100) denoting the number of test cases. Each test case starts with an integer L (1L10) denoting the length of A . The second line contains L integers A0,A1,...,AL1 (1Ai100) . The third line contains an integer Q (1Q100) denoting the number of queries. Each of next Q lines consists of four integers x0,y0,x1,y1 (0x0x1108,0y0y1108) querying the sum over the sub matrix whose upper-leftmost cell is (x0,y0) and lower-rightest cell is (x1,y1) .

Output

For each test case, print an integer representing the sum over the specific sub matrix for each query.

Sample Input

1
3
1 10 100
5
3 3 3 3
2 3 3 3
2 3 5 8
5 1 10 10
9 99 999 1000

Sample Output

1
101
1068
2238
33076541

題目概述

輸入一個長度爲L的數組a,然後按題中所給代碼構造M矩陣,進行q次詢問,每次詢問給出兩組(x,y)座標,分別表示一個矩形的左上角(x1,y1)和右下角(x2,y2),求M數組中這個矩形裏所有數的和。

思路

首先我按照題意打表發現這樣一個規律
當L爲奇數時,橫向和縱向都是每L個數一循環。
這裏寫圖片描述
當L爲偶數時,橫向和縱向都是每2L個數一循環。
這裏寫圖片描述

我們可以先處理循環矩陣裏的前綴和,
那麼每個(x,y)矩陣就是由
(x/n)*(y/n)個M[L-1][L-1]、
y/L個M[x%L][L-1]、
x/L個M[L-1][y%L]、
一個M[x%l][y%l]組成。如圖
這裏寫圖片描述

其中L是指L個數一循環,那麼很容易想到每個M[L-1][L-1]矩陣的和是一樣的,之所以是[L-1]是因爲下標是從0開始的

其次我們要求的矩形的面積就是S3 (設從原點到(x2,y2)組成矩形面積爲S)

從下圖可以看出S3=S-S1-S2+S4

這裏寫圖片描述

我們知道,每4,9,16…..個數就可以組成一個矩形,那我們不妨讓右下角的那個數用來存這個矩陣所有數的和例如
1 2 我們可以存爲 1 3
3 2 4 8
實現這一操作的代碼是

 for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(i)M[i][j]+=M[i-1][j];
                if(j)M[i][j]+=M[i][j-1];
                if(i&&j)M[i][j]-=M[i-1][j-1];
            }
        }

這樣最的目的是爲了方便S3=S-S1-S2+S4的計算

代碼
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1000;
ll n;
ll a[maxn];
ll M[maxn][maxn];
ll cal(ll x,ll y) //求從0點到(x,y)點的矩形的面積
{
    if(x<0||y<0)return 0;
    return (x/n)*(y/n)*M[n-1][n-1]+(x/n)*M[n-1][y%n]+(y/n)*M[x%n][n-1]+M[x%n][y%n];
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {

        scanf("%lld",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&a[i]);
        }
        int k=0;
        for(int i=0;i<=4*n;i++)  
        //打表,必須打4n,否則矩形右下部分將都爲0
        {
            for(int j=0;j<=i;j++)
            {
                M[j][i-j]=a[k];
                k=(k+1)%n;
            }
        }                       
        if(n%2==0)n*=2;         //判斷幾個數一循環
        for(int i=0;i<n;i++)    //用右下角的數表示矩陣所有數的和
        {
            for(int j=0;j<n;j++)
            {
                if(i)M[i][j]+=M[i-1][j];
                if(j)M[i][j]+=M[i][j-1];
                if(i&&j)M[i][j]-=M[i-1][j-1];
            }
        }
        int q;
        scanf("%d",&q);
        while(q--)
        {
            ll x1,x2,y1,y2;
            scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
            ll ans=cal(x2,y2)-cal(x1-1,y2)-cal(x2,y1-1)+cal(x1-1,y1-1);
        //用公式S3=S-S1-S2+S4求解
            printf("%lld\n",ans);
        }
    }
    return 0;
}

如有不懂 歡迎留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章