蓝桥杯2022统计子矩阵_前缀和

P2036 - [蓝桥杯2022初赛] 统计子矩阵 - New Online Judgehttp://oj.ecustacm.cn/problem.php?id=2036二维前缀和暴力能过80%的数据

#include 
typedef long long ll;
using namespace std;
ll a[512][512] = {0};
ll sum[512][512] = {0}; // sum[i][j]表示从a[1][1]到a[i][j]的和
int main() {
    ios::sync_with_stdio(false);
    int n, m, k;
    cin >> n >> m >> k;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) { // 左上角
            for (int p = i; p <= n; p++) {
                for (int q = j; q <= m; q++) { // 右下角
                    ll t = sum[p][q] - sum[p][j - 1] - sum[i - 1][q] + sum[i - 1][j - 1];
                    if (t <= k) {
                        ans++;
                    } else {
                        break;
                    }
                }
            }
        }
    }
    cout << ans;
    return 0;
}

AC代码:

#include 
typedef long long ll;
using namespace std;
const int N = 512;
int s[N][N] = {0}; // s[i]存第i行的前缀和
int main() {
    ios::sync_with_stdio(false);
    int n, m, k;
    cin >> n >> m >> k;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> s[i][j];
            s[i][j] += s[i][j - 1];
        }
    }
    for (int j1 = 1; j1 <= m; j1++) {
        for (int j2 = j1; j2 <= m; j2++) { // j1,j2枚举列数 
            int i2 = 0, sum = 0;
            for (int i1 = 1; i1 <= n; i1++) {
                while (sum <= k && i2 <= n) {
                    i2++;
                    sum += s[i2][j2] - s[i2][j1 - 1];
                }
                ans += i2 - i1;
                sum -= s[i1][j2] - s[i1][j1 - 1]; // 减去第i1行的值 
            }
        }
    }
    cout << ans;
    return 0;
}

改成一维前缀和,j1、j2枚举左右两个列号,i1、i2枚举上下两个行号,在i1++,也就是往下移时,通过上一轮的sum减去第i1行的和可以直接得到第i1+1行到i2行的和,可以减少重复计算。

最后一重循环退出的条件为:sum>k或i2往下移到底了,此时以j1、j2为列号,i1为上行号的符合条件的个数为:i2-i1

你可能感兴趣的:(算法训练,蓝桥杯,矩阵,算法)