解法一:暴力解法

每次询问都遍历小矩阵求和,时间复杂度为O(n * m * q),会超时。

解法二:前缀和

与一维前缀和类似,两步走:

第一步:预处理出一个前缀和数组

用dp[i][j]表示从[0][0]位置到[i][j]位置所有元素的和,则有:dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1] + matrix[i][j],遍历矩阵一遍,可以得到一个完整的前缀和数组

第二步:使用前缀和数组

得到前缀和数组后,可以以O(1)时间得到[x1][y1]到[x2][y2]的元素和:

为了便于处理边界情况,将matrix与dp的行和列分别扩充1。

考虑到数据的范围,将dp存储的数据类型设置为 long long类型

#include <iostream>
#include <vector>

using namespace std;

typedef long long ll;

int main()
{
    int n = 0, m = 0, q = 0;
    cin >> n >> m >> q;
    vector<vector<int>> matrix(n + 1, vector<int>(m + 1));
  	//输入数据
    for(int i = 1; i < n + 1; ++i) {
        for (int j = 1; j < m + 1; ++j) { cin >> matrix[i][j]; }
    }
    vector<vector<ll>> dp(n + 1, vector<ll>(m + 1));
  	//预处理前缀和矩阵
    for(int i = 1; i < n + 1; ++i) {
        for (int j = 1; j < m + 1; ++j) { dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1] + matrix[i][j]; }
    }
    int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
  	//使用前缀和矩阵
    while(q--)
    {
        cin >> x1 >> y1 >> x2 >> y2;
        cout << dp[x2][y2] - dp[x2][y1 - 1] - dp[x1 - 1][y2] + dp[x1 - 1][y1 - 1] << endl;
    }
    return 0;
}