前缀和

前缀 · 浏览次数 : 3

小编点评

**优化方法:** 1. **计算前缀和的总时间复杂性为 O(n),** 其中 n 是数组长度。 2. **使用动态 programming 来缓存和计算前缀和。** 3. **使用数组存储前缀和,** 而不是像原始代码那样使用循环遍历创建。 4. **使用矩阵乘法快速计算子矩阵的和。** **优化后的代码:** ```c++ #include #include using namespace std;const int N = 100010; int n, m, q; int a[N][N]; int s[N][N]; void init() { for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; } void query(int l, int r) { // calculate the prefix sum from l to r int sum = s[r][r] - (l - 1); // print the result cout << sum << endl; } int main() { scanf("%d%d%d", &n, &m, &q); init(); while (q--) { int l, r; scanf("%d%d%d%d", &l, &y1, &x2, &y2); query(l, r); } return 0; } ```

正文

前缀和

现在有一道题:

输入一个长度为 \(n\) 的整数序列。

接下来再输入 \(m\) 个询问,每个询问输入一对 \(l, r\)

对于每个询问,输出原序列中从第 \(l\) 个数到第 \(r\) 个数的和。

数据范围

\(1 \le l \le r \le n\)
\(1 \le n,m \le 100000\)
\(-1000 \le 数列中元素的值 \le 1000\)

这种题大家一看就知道打暴力,确实是个好方法

在这里插入图片描述

那么我们该如何优化它呢?
我们维护一个名为 \(s\) 的前缀和数组,且 \(s[i] = \sum\limits _ {j = 1}^{i} a[j]\),如下:

for (int i = 1; i <= n; ++i)
    s[i] = s[i - 1] + a[i];

如果我们维护的序列是 \(1,2,3,4,5,6,7,8,9,10\) 的话,那么我们的前缀和数组为 \(1,3,6,10,15,21,28,36,45,55\) ,那我们该如何利用前缀和数组的性质求和呢?
可以看下面的图:
在这里插入图片描述
假如说我们要求 \([l, r]\) 数值的和,我们只需要将 \(s[r]\) (红色部分)减去 \(s[l - 1]\) (蓝色部分)即可。代码:

printf("%d\n", s[r] - s[l - 1]);

完整代码:

#include <cstring>
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N];
int s[N];
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i)
        s[i] = s[i - 1] + a[i];
    while (m--) {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]);
    }
    return 0;
}

二维前缀和

题目:

输入一个 \(n\)\(m\) 列的整数矩阵,再输入 \(q\) 个询问,每个询问包含四个整数 \(x_1, y_1, x_2, y_2\),表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

数据范围

\(1 \le n,m \le 1000\)
\(1 \le q \le 200000\)
\(1 \le x_1 \le x_2 \le n\)
\(1 \le y_1 \le y_2 \le m\)
\(-1000 \le 矩阵内元素的值 \le 1000\)

二维前缀和,可以用来求一个矩阵里人任意一个子矩阵内数的和。
我们用 \(s[I][J]\) 表示 \(\sum\limits_{i = 1}^{I} \sum\limits_{j = 1}^{J} a[i][j]\)
所以\(s[I][J](绿色部分) = s[I - 1][J](蓝色部分) + s[I][J - 1](红色部分) - s[I - 1][J - 1] (紫色部分)+ a[I][J]\)
在这里插入图片描述
查询的话,我们将上面所有颜色的框改一下位置就好了;假如我们要求 \((x_1, y_1)\)\((x_2, y_2)\) 的和,即:\(s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]\)
代码:

#include <cstring>
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N];
int s[N][N];
int main() {
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &a[i][j]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
    while (q--) {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n",
               s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
    }
    return 0;
}

与前缀和相似的内容:

前缀和

# 前缀和 现在有一道题: > 输入一个长度为 $n$ 的整数序列。 > > 接下来再输入 $m$ 个询问,每个询问输入一对 $l, r$。 > > 对于每个询问,输出原序列中从第 $l$ 个数到第 $r$ 个数的和。 > #### 数据范围 > > $1 \le l \le r \le n$ >

使用前缀和数组解决"区间和查询"问题

本文已收录到 GitHub · AndroidFamily,有 Android 进阶知识体系,欢迎 Star。技术和职场问题,请关注公众号 [彭旭锐] 进 Android 面试交流群。 前言 大家好,我是小彭。 今天分享到一种非常有趣的数据结构 —— 前缀和数组。前缀和的思想本身很容易理解,同时也是

LeetCode 周赛 338,贪心 / 埃氏筛 / 欧氏线性筛 / 前缀和 / 二分查找 / 拓扑排序

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 上周末是 LeetCode 第 338 场周赛,你参加了吗?这场周赛覆盖的知识点很多,第四题称得上是近期几场周赛的天花板。 小彭的技术交流群 02 群来了,公众号回复 “加群” 加入我们~

LeetCode 周赛 340,质数 / 前缀和 / 极大化最小值 / 最短路 / 平衡二叉树

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 上周跟大家讲到小彭文章风格的问题,和一些朋友聊过以后,至少在算法题解方面确定了小彭的风格。虽然竞赛算法题的文章受众非常小,但却有很多像我一样的初学者,他们有兴趣参加但容易被题目难度和大神选

LeetCode 周赛上分之旅 #44 同余前缀和问题与经典倍增 LCA 算法

> ⭐️ **本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 \[彭旭锐] 和 [BaguTree Pro](https://www.mdnice.com/writing/85b28c4e60354865a423728e668fc570) 知识星球提问。** > > 学习数据

算法学习笔记(∞):杂项

杂项 目录杂项代码规范算法优化的本质记忆化搜索基于边的记忆化动态规划树上每一个点求答案计数题关于仙人掌 DAG 的拓扑序计数关于微扰贪心的证明组合数前缀和单位根反演\(O(n^2)\) 状态求和矩形式子求和\(O(n^2)\) 状态 \(O(n)\) 单点问题CDQ 分治FFT 循环卷积根号多项式算

数据库系列16:MyISAM与InnoDB的索引对比

相关文章 数据库系列:MySQL慢查询分析和性能优化 数据库系列:MySQL索引优化总结(综合版) 数据库系列:高并发下的数据字段变更 数据库系列:覆盖索引和规避回表 数据库系列:数据库高可用及无损扩容 数据库系列:使用高区分度索引列提升性能 数据库系列:前缀索引和索引长度的取舍 数据库系列:MyS

【数据结构和算法】Trie树简介及应用详解

Trie树,即字典树,又称单词查找树或键树,是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

前缀树(Tire)—Python

核心思想 空间换时间,是一种用于快速查询的多叉树结构,利用字符串的公共前缀来降低时间 优缺点: 优点:查询效率高,减少字符比较 缺点:内存消耗较大 每次都会从头向下一直到字符串结尾 前缀树 1 单个字符串从前到后加到一棵多叉树上 2 每隔字符串都会有自己所在节点的两个属性path和end,path代

[转帖]RedisTemplate写入Redis数据出现无意义乱码前缀\xac\xed\x00\x05

背景 项目使用Spring的RedisTemplate进行Redis数据存取操作,实际应用中发现Redis中key和value会出现“无意义”乱码前缀\xac\xed\x00\x05t\x00-(样例\xac\xed\x00\x05t\x00-abcd:abc:xxxxxx:passport:ass