"Algorithm Competition·Quick 300 Questions" One question per day: "Matrix"

"Algorithm Competition·Quickly Punch 300 Questions" will be published in 2024. It is the "Algorithm Competition"'s auxiliary exercise book.
All questions are placed in the self-built OJ New Online Judge.
Codes are given in three languages: C/C++, Java, and Python. The topics are mainly mid- to low-level topics and are suitable for entry-level and advanced students.


Prime Number Puzzle Game ”, link: http://oj.ecustacm.cn/problem.php?id=1814

Question description

[Problem Description] Given two nn matrices A and B, note C=AB (matrix multiplication here), there are m queries.
   Ask the sum of all numbers in a sub-matrix in C each time.
   Each time the query is given four numbers a, b, c, d, it means that the submatrix sought is the submatrix from row a and column b to row c and column d.
[Input format] The first line of input is n and m (1≤n≤2000, m≤50000).
   Next n lines, each line of n numbers represents matrix A.
   Next n rows, each row of n numbers represents matrix B. Each number in the matrix cannot exceed 100.
   The next m lines, each row of 4 numbers a, b, c, d represent the sub-matrix of the query, (1≤a,b,c,d≤n).
   This question requires a large amount of input data, so it is recommended to use fast reading.
[Output format] For each set of questions, output a line containing a number representing the answer.
[Input sample]

3 2
1 9 8
3 2 0
1 8 3
9 8 4
0 5 15
1 9 6
1 1 3 3
2 3 1 2

【Output sample】

661
388

answer

   If you only need to ask the sum of sub-matrix numbers of a given matrix, it is a very straightforward application of prefix sum.
To quickly obtain the sum of any submatrices of a matrix, you can use "two-dimensional prefix sum". Define the two-dimensional array s[][], s [ i ] [ j ] s[i][j] s[i][ j]Display child square [ 1 , 1 ] [ i , j ] [1, 1] ~ [i, j] [1,1] [i,The sum of j]. After precomputing s[][], any submatrix sum can be quickly calculated. As shown in the figure below, shadow submatrix [ i 1 , j 1 ] [ i 2 , j 2 ] [i_1, j_1] ​​~ [i_2, j_2] [i1,j1] [i2,j2]'s sum equality:
     s [ i 2 ] [ j 2 ] − s [ i 2 ] [ j 1 − 1 ] − s [ i 1 − 1 ] [ j 2 ] + s [ i 1 − 1 ] [ j 1 − 1 ] s[i_2][j_2] - s[i_2][j_1-1] - s[i_1-1][ j_2] + s[i_1-1][j_1-1] s[i2][j2]s[i2][j11]s[i11][j2]+s[i11][j11]
  Inside s [ i 1 − 1 ] [ j 1 − 1 ] s[ i_1-1][ j_1-1] s[i11][j11] has been subtracted 2 times and needs to be added back 1 time.
  Use the above formula to query the sub-matrix sum, and the calculation amount is only O(1).
Insert image description here
  Precompute all s[][] of a matrix A, the calculation amount is n 2 n^2 n2. The code is written like this:

for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            cin >> A[i][j], s[i][j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+A[i][j];//预计算s[][]

  If you use the above method for this question, you need to first calculate matrix multiplication C=A*B. But the calculation amount of matrix multiplication is n 3 n^3 n3, and n≤2000, it will definitely time out, so direct calculation of matrix multiplication must be avoided.
  Let’s analyze the calculation process of matrix multiplication C=A*B to see if we can use the prefix sum to reduce the amount of calculation. The figure below shows the details of matrix multiplication, finding the sum of C neutron matrices (a, b) ~ (c, d).
Insert image description here
(1) Calculate the interval sum of column b of C, that is, C [ a ] ​​[ b ] + C [ a + 1 ] [ b ] + . . . + C [ c ] [ b ] C[a][b] + C[a+1][b] + ... + C[c][b] C[a][b]+C[a+1][b]+...+C[c][ b].
  Pre-view C middle b column ’*’ C [ a ] ​​[ b ] C[a][b] C[a][ b]'s calculation process, 它等于A row a to B column b:
     C [ a ] ​​[ b ] = A [ a ] ​​[ 1 ] × B [ 1 ] [ b ] + A [ a ] ​​[ 2 ] × B [ 2 ] [ b ] + . n ] × B [ n ] [ b ] C[a][b] = A[a][1]×B[1][b] + A[a][2]×B[2][b] + ... + A[a][n]×B[n][b] C[a][b]=A[a][1]×B[1][b]+A[a][2]×B[2][b]+...+A[a][n]×B[n][ b]
  Same theory, the calculation process for the bth column in C and other symbols is:
     C [ a + 1 ] [ b ] = A [ a + 1 ] [ 1 ] × B [ 1 ] [ b ] + A [ a + 1 ] [ 2 ] × B [ 2 ] [ b ] + . . . + A [ a + 1 ] [ n ] × B [ n ] [ b ] C[a+1][b] = A[a+1][1]×B[1][b] + A[a+1 ][2]×B[2][b] + ...+ A[a+1][n]×B[n][b] C[a+1][b]=A[a+1][1]×B[1][b]+A[a+1][2]×B[2][b]+...+A[a+1][n]×B[n][b]
    …
     C [ c ] [ b ] = A [ c ] [ 1 ] × B [ 1 ] [ b ] + A [ c ] [ 2 ] × B [ 2 ] [ b ] + . . . + A [ c ] [ n ] × B [ n ] [ b ] C[c][b] = A[c][1]×B[1][b] + A[c][2]×B[2][b] + ... +A[c][n]×B[n][b] C[c][b]=A[c][1]×B[1][b]+A[c][2]×B[2][b]+...+A[c][n]×B[n][ b] (Formula 3-1)
  Hold (Formula 3-1) Upper and lower addition To get C's child square b column's division sum:
     C [ a ] ​​[ b ] + C [ a + 1 ] [ b ] + . . . + C [ c ] [ b ] C[a][b] + C[a+1][b] + ... + C[c][b] C[a][b]+C[a+1][b]+...+C[c][b]
     = ( A [ a ] [ 1 ] + A [ a + 1 ] [ 1 ] + . . . + A [ c ] [ 1 ] ) × B [ 1 ] [ b ] + = (A[a][1]+A[a+1][1] + ... + A[c][1])×B[1][b] + =(A[a][1]+A[a+1][1]+...+A[c][1])×B[1][b]+
     ( A [ a ] [ 2 ] + A [ a + 1 ] [ 2 ] + . . . + A [ c ] [ 2 ] ) × B [ 2 ] [ b ] + (A[a][2]+A[a+1][2] + ... + A[c][2])×B[2][b] + (A[a][2]+A[a+1][2]+...+A[c][2])×B[2][b]+
     …
     ( A [ a ] [ n ] + A [ a + 1 ] [ n ] + . . . + A [ c ] [ n ] ) × B [ n ] [ b ] (A[a][n]+A[a+1][n] + ... + A[c][n])×B[n][b] (A[a][n]+A[a+1][n]+...+A[c][n])×B[n][ b] (Formula 3-2)
  A[a][1] +A[a+1][1]+…+A[c][1] Right and right is the first column of A, A[a][2]+A[a+1][2]+… +A[c][2]This is the second column of terms,..., etc.
  记s1[][j]为A's jth column precombination, with:
     A [ a ] ​​[ 1 ] + A [ a + 1 ] [ 1 ] + . . . + A [ c ] [ 1 ] = s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] A[a][1]+A[a+1] [1]+...+A[c][1] = s1[c][1] - s1[a-1][1] A[a][1]+A[a+1][1]+...+A[c][1]=s1[c][1]s1[a1][1]
     A [ a ] ​​[ 2 ] + A [ a + 1 ] [ 2 ] + . . . + A [ c ] [ 2 ] = s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] A[a][2]+A[a+1][2]+...+ A[c][2] = s1[c][2] - s1[a-1][2] A[a][2]+A[a+1][2]+...+A[c][2]=s1[c][2]s1[a1][2]
    …
     A [ a ] [ n ] + A [ a + 1 ] [ n ] + . . . + A [ c ] [ n ] = s 1 [ c ] [ n ] − s 1 [ a − 1 ] [ n ] A[a][n]+A[a+1][n] + ... + A[c][n]=s1[c][n] - s1[a-1][n] A[a][n]+A[a+1][n]+...+A[c][n]=s1[c][n]s1[a1][n]
  C's child square b-th column's partition sum (Formula 3-2) Simplification:
     C [ a c ] [ b ] C[a~c][b ]C[a c][b]
     = ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × B [ 1 ] [ b ] + ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × B [ 2 ] [ b ] + . . . + s 1 [ c ] [ n ] − s 1 [ a − 1 ] [ n ] × B [ n ] [ b ] = (s1[c][1] - s1[a-1][1])×B[1][b] + (s1[c][2] - s1[a-1][2])×B[2][b] + ...+s1[c][n] - s1[a-1][n]×B[n][b] =(s1[c][1]s1[a1][1])×B[1][b]+(s1[c][2]s1[a1][2])×B[2][b]+...+s1[c][n]s1[a1][n]×B[n][ b]
(2) Calculate the sum of the submatrices of C, that is, put the b-th column, b+1 column,... , add columns d. According to the discussion in (1), there are:
     C [ a c ] [ b ] + C [ a c ] [ b + 1 ] + . . . + C [ a c ] [ d ] C[a~c][b] + C[a~c][b+1] + ... + C[a~c][d] C[a c][b]+C[a c][b+1]+...+C[a c][d]
     = ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × B [ 1 ] [ b ] + ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × B [ 2 ] [ b ] + . . . = (s1[c][1] - s1[a-1][1])×B[1][b] + (s1[c][2] - s1[a-1][2])×B[2][b] + ... =(s1[c][1]s1[a1][1])×B[1][b]+(s1[c][2]s1[a1][2])×B[2][b]+...
     ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × B [ 1 ] [ b + 1 ] + ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × B [ 2 ] [ b + 1 ] + . . . (s1[c][1] - s1[a-1][1])×B[1][b+1] + (s1[c][2] - s1[a-1][2])×B[2][b+1] + ... (s1[c][1]s1[a1][1])×B[1][b+1]+(s1[c][2]s1[a1][2])×B[2][b+1]+...
     ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × B [ 1 ] [ b + 2 ] + ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × B [ 2 ] [ b + 2 ] + . . . (s1[c][1] - s1[a-1][1])×B[1][b+2] + (s1[c][2] - s1[a-1][2])×B[2][b+2] + ... (s1[c][1]s1[a1][1])×B[1][b+2]+(s1[c][2]s1[a1][2])×B[2][b+2]+...
    …
     ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × B [ 1 ] [ d ] + ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × B [ 2 ] [ d ] + . . . (s1[c][1] - s1[a-1][1])×B[1][d] + (s1[c][2] - s1[a-1][2])×B[2][d] + ... (s1[c][1]s1[a1][1])×B[1][d]+(s1[c][2]s1[a1][2])×B[2][d]+... (Formula 3-3)
  Hold (Formula 3-3) Upper and lower addition, obtained:
    C[a c][b]+C[a c][b+1]+...+C[a c][d]
     = ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × ( B [ 1 ] [ b ] + B [ 1 ] [ b + 1 ] + . . . + B [ 1 ] [ d ] ) + = (s1[c][1] - s1[a-1][1]) × (B[1][b]+B[1][b+1] + ...+ B[1][d]) + =(s1[c][1]s1[a1][1])×(B[1][b]+B[1][b+1]+...+B[1][d])+
     ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × ( B [ 2 ] [ b ] + B [ 2 ] [ b + 1 ] + . . . + B [ 2 ] [ d ] ) + (s1[c][2] - s1[a-1][2]) × (B[2][b]+B[2][b+1] + ... + B[2][d]) + (s1[c][2]s1[a1][2])×(B[2][b]+B[2][b+1]+...+B[2][d])+
    …
     ( s 1 [ c ] [ n ] − s 1 [ a − 1 ] [ n ] ) × ( B [ n ] [ b ] + B [ n ] [ b + 1 ] + . . . + B [ n ] [ d ] ) (s1[c][n] - s1[a-1][n]) × (B[n][b]+B[n][b+1] + ... + B[n][d]) (s1[c][n]s1[a1][n])×(B[n][b]+B[n][b+1]+...+B[n][ d]) (Formula 3-4)
  Notes2[i][]为B The i-th line of the previous combination, with:
     B [ 1 ] [ b ] + B [ 1 ] [ b + 1 ] + . . . + B [ 1 ] [ d ] = s 2 [ 1 ] [ d ] − s 2 [ 1 ] [ b − 1 ] B[1][b]+B[1][b+1] + ...+ B[1][d] = s2[ 1][d] - s2[1][b-1] B[1][b]+B[1][b+1]+...+B[1][d]=s2[1][d]s2[1][b1]
     B [ 2 ] [ b ] + B [ 2 ] [ b + 1 ] + . . . + B [ 2 ] [ d ] = s 2 [ 2 ] [ d ] − s 2 [ 2 ] [ b − 1 ] B[2][b]+B[2][b+1] + ...+ B[2][d] = s2[2][d] - s2[2][b-1] B[2][b]+B[2][b+1]+...+B[2][d]=s2[2][d]s2[2][b1]
    …
     B [ n ] [ b ] + B [ n ] [ b + 1 ] + . . . + B [ n ] [ d ] = s 2 [ n ] [ d ] − s 2 [ n ] [ b − 1 ] B[n][b]+B[n][b+1] + ... + B[n][d]=s2[n][d] - s2[n][b-1] B[n][b]+B[n][b+1]+...+B[n][d]=s2[n][d]s2[n][b1]
  则(Formula 3-4) Reproduction:
     C [ a c ] [ b ] + C [ a c ] [ b + 1 ] + . . . + C [ a c ] [ d ] C[a~c][b] + C[a~c][b+1] + .. . + C[a~c][d] C[a c][b]+C[a c][b+1]+...+C[a c][d]
     = ( s 1 [ c ] [ 1 ] − s 1 [ a − 1 ] [ 1 ] ) × ( s 2 [ 1 ] [ d ] − s 2 [ 1 ] [ b − 1 ] ) + = (s1[c][1] - s1[a-1][1]) × ( s2[1][d] - s2[1][b-1]) + =(s1[c][1]s1[a1][1])×(s2[1][d]s2[1][b1])+
     ( s 1 [ c ] [ 2 ] − s 1 [ a − 1 ] [ 2 ] ) × ( s 2 [ 2 ] [ d ] − s 2 [ 2 ] [ b − 1 ] ) + (s1[c][2] - s1[a-1][2]) × ( s2[2][d] - s2[2][b-1]) + (s1[c][2]s1[a1][2])×(s2[2][d]s2[2][b1])+
    …
     ( s 1 [ c ] [ n ] − s 1 [ a − 1 ] [ n ] ) × ( s 2 [ n ] [ d ] − s 2 [ n ] [ b − 1 ] ) (s1[c][n] - s1[a-1][n]) × ( s2[n][d] - s2[n][b-1]) (s1[c][n]s1[a1][n])×(s2[n][d]s2[n][b1])
  This is the final formula. Each line is the multiplication of the sum of two intervals. There are n lines in total, n times. Multiplication calculation.
  What is the total calculation amount? (1) Precalculate s1[][] and s2[][], which is O ( n 2 ) O(n^2) O(n O ( m n ) O(mn) (3) Calculation amount etc. O ( n 2 ) + O ( m n ) O(n^2) + O(mn) O(n2)+O(mn),刚Good通过测试。

[Key points] Prefix sum, matrix calculation.

C++ code

   The question mentions "The input data for this question is large, so it is recommended to use fast reading."
   The standard input and output functions of C++ are cin/cout and scanf/printf. By default, cin/cout is much slower than scanf/printf. In situations where a large amount of input and output is required, scanf and printf are generally sufficient. If you still want to increase the speed, use getchar() for input and putchar() for output, they are faster.
   Write a fast reading function read() yourself and use getchar(). The function of getchar() is to read 1 byte of data according to the char type. The read() in the code below is a fast reading template for integer input. Use getchar() to read each character and then convert it into a number. For example, enter "245", use getchar() to read '2', '4', and '5' three times, and then combine them into the number "345". Note that there may be negative numbers, so you need to judge the ‘-’ sign.
   Write a quick write function write() yourself, using putchar(). The function of putchar() is to output a character. When you need to output a number, convert each bit of it into a character, and then use putchar() to output it.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010;
int n,m,a,b,c,d;
int A[N][N],B[N][N],s1[N][N],s2[N][N];
inline int read(int &x) {
    
             //快读int型整数。如果需要读long long,把int改成long long
    x = 0;
    int w = 1;//w:判断正负号
    char ch = 0;
    while (ch < '0' || ch > '9') {
    
     //读字符
        if (ch == '-') w = -1;     //这是一个负整数数
        ch = getchar();            //读一个字符
    }
    while (ch >= '0' && ch <= '9') {
    
     //读数字
        x = x * 10 + (ch - '0');
        ch = getchar();
    }
    return x = x * w;
}
void write(ll x) {
    
                    //快写long long型整数
    if (x < 0) {
    
                      // 判断正负。如果是负数,输出负号
        putchar('-');      
x = -x;                   //记得把负数变正,方便下面输出数字         
    }
    if (x > 9) write(x / 10);     // 递归,将除最后一位外的其他部分放到递归中输出
    putchar(x % 10 + '0');        // 已经输出(递归)完 x 末位前的所有数字,输出末位
}
ll query(int a,int b,int c,int d){
    
         //C=A*B,计算C的子矩阵和
    ll ans = 0;
    for(int k=1;k<=n;k++){
    
    
        ll ans1 = s1[c][k] - s1[a-1][k];
        ll ans2 = s2[k][d] - s2[k][b-1];
        ans += ans1*ans2;
    }
    return ans;
}
int main(){
    
    
    read(n),read(m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            read(A[i][j]), s1[i][j] = s1[i-1][j]+A[i][j];   //输入A。s1[][j]是第j列的前缀和
                  //read(A[i][j])等于scanf("%d",&A[i][j])或cin>>A[i][j]
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            read(B[i][j]), s2[i][j] = s2[i][j-1]+B[i][j];   //输入B。s2[i][]是第i行的前缀和
    while(m--){
    
    
        read(a),read(b),read(c),read(d);  //等于scanf("%d%d%d%d",&a,&b,&c,&d);
        if(a > c) swap(a, c);             //可能存在a>c、b>d的情况
        if(b > d) swap(b, d);
        ll ans = query(a,b,c,d);
        write(ans); putchar('\n');       //等于printf("%lld\n",query(a,b,c,d));
    }
    return 0;
}

Java code

import java.util.*;  
import java.io.*; 
class Main {
    
    
    static FastReader scanner = new FastReader();
    static int N = 2010;
    static int n, m, a, b, c, d;
    static int[][] A = new int[N][N], B = new int[N][N], s1 = new int[N][N], s2 = new int[N][N];
     public static void main(String[] args) throws IOException {
    
    
        n = scanner.nextInt();
        m = scanner.nextInt(); 
        for (int i = 1; i <= n; i++) 
            for (int j = 1; j <= n; j++) {
    
    
                A[i][j] = scanner.nextInt();;
                s1[i][j] = s1[i - 1][j] + A[i][j];
            } 
        for (int i = 1; i <= n; i++) 
            for (int j = 1; j <= n; j++) {
    
    
                B[i][j] = scanner.nextInt();;
                s2[i][j] = s2[i][j - 1] + B[i][j];
            } 
        while (m-- > 0) {
    
    
            a = scanner.nextInt();
            b = scanner.nextInt();
            c = scanner.nextInt();
            d = scanner.nextInt();
            if (a > c) {
    
     int temp = a;  a = c;  c = temp;  }
            if (b > d) {
    
     int temp = b;  b = d;  d = temp;  }
            long ans = query(a, b, c, d);
            System.out.println(ans);
        } 
    } 
    static long query(int a, int b, int c, int d) {
    
    
        long ans = 0;
        for (int k = 1; k <= n; k++) {
    
    
            long ans1 = s1[c][k] - s1[a - 1][k];
            long ans2 = s2[k][d] - s2[k][b - 1];
            ans += ans1 * ans2;
        }
        return ans;
    } 
    static class FastReader {
    
    
        BufferedReader br;
        StringTokenizer st;  
        public FastReader() {
    
    
            br = new BufferedReader(new InputStreamReader(System.in));
        }  
        String next() {
    
    
            while (st == null || !st.hasMoreElements()) {
    
    
                try {
    
    st = new StringTokenizer(br.readLine());} 
                catch (IOException e) {
    
     e.printStackTrace(); }
            }
            return st.nextToken();
        }  
        int nextInt() {
    
         return Integer.parseInt(next());    }  
        long nextLong() {
    
       return Long.parseLong(next());      }  
        double nextDouble() {
    
     return Double.parseDouble(next());     }  
        String nextLine() {
    
    
            String str = "";
            try {
    
     str = br.readLine();  } 
            catch (IOException e) {
    
      e.printStackTrace();   }
            return str;
        }
    }
}

Python code

  

#pypy
import sys
input = sys.stdin.readline
def query(a, b, c, d):
    ans = 0
    for k in range(1, n+1):
        ans1 = s1[c][k] - s1[a-1][k]
        ans2 = s2[k][d] - s2[k][b-1]
        ans += ans1 * ans2
    return ans
n, m = list(map(int, input().split()))
N = n+1
s1 = [[0] * N for _ in range(N)]
s2 = [[0] * N for _ in range(N)]
A = [0] * N
B = [0] * N 
for i in range(1, n+1):
    A[i] = [0] + list(map(int, input().split()))
    for j in range(1, n+1):  s1[i][j] = s1[i-1][j] + A[i][j]   
for i in range(1, n+1):
    B[i] = [0] + list(map(int, input().split()))
    for j in range(1, n+1):  s2[i][j] = s2[i][j-1] + B[i][j]     
for _ in range(m):
    a, b, c, d = list(map(int, input().split()))
    if a > c:   a, c = c, a
    if b > d:   b, d = d, b
    sys.stdout.write(str(query(a, b, c, d)) + '\n')

Guess you like

Origin blog.csdn.net/weixin_43914593/article/details/133203020