#9058.「JYTOI Round 1 」一些矩阵 题解 审核通过

CPP 刷题王 2025-07-07 9:08:33 2025-07-11 13:02:03 4

如果大家打过最近某场 ABC 的 F,那相信难不倒大家。

注意到 很小,所以我们可以使用套路:枚举第 行和第 行,再统计前 列在第 行之间的和。

注意到所有数都大于等于 ,因此前 列在第 行之间的和应该是单调不减的。

如果将其转化为一维怎么做?

由于 ,所以我们只需要找到一个 满足 。由于 在哪里没有关系,所以可以用一些具有单调性的数据结构维护在已经算出来的 中有多少是满足这个条件的,即满足 。比如可以用 set 然后计算区间的贡献即可。

但是这样的算法是 的,但是计算一下就会发现约为 。大概率会超时。

但是我们发现我们可以用单调栈来维护,于是就变成 。才 多一点,但是时限 1.5s,不会 T 的。

注意:,所以需要使用 unsigned long long

CODE:

#include <bits/stdc++.h>
using namespace std;
#define intt unsigned long long
intt sum[60][50010];
intt st[50010], ans;
int ll, rr, top;
signed main() {
    ios::sync_with_stdio(false);
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int n, m;
    intt l, r;
    cin >> n >> m;
    intt c;
    for (int i = 1, j; i <= n; i++) {
        for (j = 1; j <= m; j++) {
            cin >> c;
            sum[i][j] += c;
        }
    }
    cin >> l >> r;
    for (int i = 1, j; i <= n; i++) {
        for (j = 1; j <= m; j++) {
            sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
        }
    }
    intt t;
    for (int i = 1, i2, j; i <= n; i++) {
        for (i2 = i; i2 <= n; i2++) {
            ll = 1, rr = 1, top = 1;
            for (j = 1; j <= m; j++) {
                t = sum[i2][j] - sum[i - 1][j];  // t 具有单调性。
                //需要将 t - x >= l && t - x <= r    →   t - r <= x <= t - l
                while (ll <= top && t - st[ll] > r) {
                    ll++;
                }
                while (rr <= top && t - st[rr] >= l) {
                    rr++;
                }
                while (rr && t - st[rr] < l ||
                       rr > top) {  //需要回退,因为可能加过头了,还因为只有像上面那样写才有单调性。
                    rr--;
                }
                if (t - st[ll] <= r && t - st[rr] >= l && rr >= ll) {
                    ans += rr - ll + 1;
                }
                st[++top] = t;
            }
        }
    }
    cout << ans;
    return 0;
}
{{ vote && vote.total.up }}