• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

RomanLin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

【带权前缀和】codeforces 2044 H. Hard Demon Problem

题目

https://codeforces.com/problemset/problem/2044/H

题意

第一行,输入一个正整数 \(T(1 \leq T \leq 1000)\),代表总共 \(T\) 组测试用例。对于每组测试用例:第一行输入两个正整数 \(n, q(1 \leq n \leq 2000, 1 \leq q \leq 10^6)\),随后输入一个 \(n \times n\) 的矩阵 \(a(1 \leq a_{i, j} \leq 10^6)\),最后输入 \(q\) 个询问,每个询问输入四个正整数 \(r_1, c_1, r_2, c_2(1 \leq r_1 \leq r_2 \leq n, 1 \leq c_1 \leq c_2 \leq n)\),代表我们要截取出左上角为 \((r_1, c_1)\) 和右下角为 \((r_2, c_2)\) 的子矩阵。

对于每个询问,我们要计算出 \(1 \times a[r_1][c_1] + 2 \times a[r_1][c_1 + 1] + ... + k * a[r_2][c_2]\) 的值,其中 \(k\) 为子矩阵的元素个数。

保证:所有 \(n\) 之和小于等于 \(2000\)。

题解

对于带权前缀和,可以先学习灵神的视频:https://www.bilibili.com/video/BV1hQ4y1L7Tk/?vd_source=a7061d90bb9470aa775ae3cdb7d30738

对于算式$$1 \times a[r_1][c_1] + 2 \times a[r_1][c_1 + 1] + ... + k * a[r_2][c_2]$$
可以视为:$$\sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{[(j - c_1 + 1) + (i - r_1) \times (c_2 - c_1 + 1)] \times a_{i,j}} = \sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{j \times a_{i,j}} + \sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{(c_2 - c_1 + 1) \times i \times a_{i,j}} + \sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{[1 - c_1 - r_1 \times (c_2 - c_1 + 1)] \times a_{i,j}}$$

对于 \(\sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{j \times a_{i,j}}\) 和 \(\sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{(c_2 - c_1 + 1) \times i \times a_{i,j}}\) 都可以用带权前缀和数组的二维前缀和进行维护;对于 \(\sum_{i=r_1,j=c_1}^{i=r_2, j=c_2}{[1 - c_1 - r_1 \times (c_2 - c_1 + 1)] \times a_{i,j}}\) 只需要维护原矩阵的二维前缀和即可。

时间复杂度:\(O(n^2 + q)\)
空间复杂度:\(O(n ^ 2)\)

参考代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

constexpr int N = 2007;
int T, n, q, r1, r2, c1, c2;
ll a[N][N];//前缀和
ll b[N][N];//带权前缀和(列)
ll c[N][N];//带权前缀和的前缀和(b)
ll d[N][N];//带权前缀和(行)
ll e[N][N];//带权前缀和的前缀和(d)

void solve() {
    cin >> n >> q;
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            cin >> a[i][j];
            b[i][j] = j * a[i][j];
            b[i][j] += b[i][j - 1];
            c[i][j] = b[i][j] + c[i - 1][j];
            d[i][j] = i * a[i][j];
            d[i][j] += d[i - 1][j];
            e[i][j] = d[i][j] + e[i][j - 1];
            a[i][j] += a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1];
        }
    }
    while (q --) {
        cin >> r1 >> c1 >> r2 >> c2;
        ll csz = c2 - c1 + 1;
        ll ans = c[r2][c2] - c[r2][c1 - 1] - c[r1 - 1][c2] + c[r1 - 1][c1 - 1];
        ans += csz * (e[r2][c2] - e[r2][c1 - 1] - e[r1 - 1][c2] + e[r1 - 1][c1 - 1]);
        ans += (1LL - r1 * csz - c1) * (a[r2][c2] - a[r2][c1 - 1] - a[r1 - 1][c2] + a[r1 - 1][c1 - 1]);
        cout << ans << ' ';
    }
    cout << '\n';
}

int main() {
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    cin >> T;
    while (T --) {
        solve();
    }
    return 0;
}

posted on 2025-01-04 16:55  RomanLin  阅读(82)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3