首页 > 其他分享 >前缀和学习笔记与总结

前缀和学习笔记与总结

时间:2023-07-03 20:22:37浏览次数:37  
标签:总结 题目 前缀 int 矩阵 笔记 cdots 模板

前缀和学习笔记与总结

目录

前缀和

一维前缀和

What

现有 原数组

\[a_1,a_2,a_3,\ldots,a_n \]

对应的 前缀和数组 应满足:

\[S_i = a_1+a_2+a_3+\cdots+a_n \]

前缀和 \(S_i\) 即为 原数组 中前 \(i\) 个数的和

如何求

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

i = 1 开始 和 定义 s[0] = 0,是为了解决边界问题。

对于求区间 \(\left[ l, r \right]\) 的和,可通过 s[r] - s[l - 1]
证明过程如下:

\[\begin{aligned} S_r &= a_1 + a_2 + \cdots + a_{l - 1} + a_l + \cdots + a_r \\ S_{l - 1} &= a_1 + a_2 + \cdots + a_{l - 1} \\ \\ S_r &- S_{l - 1} = a_l + \cdots + a_r = \sum_{i = l}^{r}a_i \\ \end{aligned} \]

前缀和处理为 \(O(N)\),查询为 \(O(1)\)。

作用

快速地求出原数组中 连续 一段数的
(由 \(O(n)\) 优化到 \(O(1)\))

公式

\[\begin{aligned} &S_r = a_1 + a_2 + \cdots + a_{l - 1} + a_l + \cdots + a_r \\ &S_r - S_{l - 1} = a_l + \cdots + a_r \end{aligned} \]

模板

S[i] = a[1] + a[2] + ... a[i];
a[l] + ... + a[r] = S[r] - S[l - 1];

模板题目

AcWing 795. 前缀和 题目入口

题目大意

输入一个长度为 \(n\) 的整数序列。
接下来再输入 \(m\) 个询问,每个询问输入一对 \(l,r\)。
对于每个询问,输出原序列中从第 \(l\) 个数到第 \(r\) 个数的和。

CODE

点击查看代码
#include <iostream>

using namespace std;

const int N = 100010;

int n, m;
int a[N], 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;
}

二维前缀和

What

现有一个矩阵

如图

阴影部分表示 \(S_{4,3}\),即 左上端点为 \((1,1)\),右下端点为 \((4,3)\) 的矩阵 中数的总和

所以 \(S_{i,j}\) 就是下图中的阴影部分的总和

\(S_{i,j}\) 怎么算

同样,我们也采用递推的方式,用前面已经求出的 \(S\) 来求 \(S_{i,j}\)。

对于 原数组 \(A\),前缀和数组 \(S\),如下图

\(S_{i-1,j}\) 与 \(S_{i,j-1}\) 相加将多出一个 \(S_{i-1,j-1}\)(即紫色重叠部分),所以需要减去一个 \(S_{i-1,j-1}\).
在加上 \((i,j)\) 本身,即加上 \(A_{i,j}\).

所以

\[S_{i,j}=S_{i-1,j}+S_{i,j-1}-S_{i-1,j-1}+A_{i,j} \]

for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &s[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];

矩阵的和

对于 左上端点为 \((x_1,y_1)\),右下端点为 \((x_2,y_2)\) 的矩阵

如图

用 \(S_{x_2,y_2}\) 减去 \(S_{x_2,y_1-1}\) 与 \(S_{x_1-1,y_2}\),\(S_{x_1-1,y_1-1}\)(紫色部分)被多减了一次。

所以

\[Sum = S_{x_2,y_2}-S_{x_2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1} \]

Sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]

公式

\[S_{i,j}=S_{i-1,j}+S_{i,j-1}-S_{i-1,j-1}+A_{i,j} \]

\[Sum = S_{x_2,y_2}-S_{x_2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1} \]

模板

S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &s[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];

Sum = S_{x_2,y_2}-S_{x_2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1}

模板题目

AcWing 796. 子矩阵的和 题目入口

题目大意

输入一个 \(n\) 行 \(m\) 列的整数矩阵,再输入 \(q\) 个询问,每个询问包含四个整数 \(x1,y1,x2,y2\),表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。

CODE

点击查看代码
#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
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", &s[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];

    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;
}


标签:总结,题目,前缀,int,矩阵,笔记,cdots,模板
From: https://www.cnblogs.com/MingruiYang/p/17523910.html

相关文章

  • 2023年暑假集训总结/7.1
    6-26T1多米诺骨牌Hades与Dionysus在狂饮后玩起了多米诺骨牌的小游戏。现在桌上有n块多米诺骨牌,每块多米诺骨牌上半部分和下半部分上都有一个整数。每次翻转可让一块多米诺骨牌上下翻转,即上下部分数交换。Hades想让n块骨牌上半部分的数加起来是一个偶数,而Dionys......
  • 【JS错误总结】promise.then 如果没有被 resolve,不会立即执行,而是先执行宏任务,等待 pr
    setTimeout(()=>{console.log('setTimeout')},0)letpromise=newPromise((resolve,reject)=>{console.log('1')setTimeout(()=>{console.log('timeStart')resolve('success�......
  • 2023年暑假集训总结/7.3
    2023年暑假集训总结/7.3预估成绩:100+50+40+20=210实际成绩:100+25+24+25=174T1房题意:有n个已知中心和长度且互不重合的区间,问有多少个长度为t的区间恰好与其中一个区间的一个端点相等,且不与所有区间重合思路&做法:签到题,注意到答案上界为2n,只需要依次枚举接在每个区间左右......
  • C++学习笔记
    类型兼容不同类型的数据在一定条件下可以进行转换,比如intn='a',是将字符'a'赋值给整型变量n,在赋值过程中发生了隐式类型转换,字符类型的数据转换为整型数据。这种现象称为类型转换,也称为类型兼容。继承与派生继承方式public继承private继承protect继承类型兼容在C++中,基类与派生......
  • 7.3总结
    上午起床之后送妹妹上学,回来后在床上躺了会,然后做pta,现在对于20分的题做起来很吃力,但是要是把题一点一点看明白,还是能够做得出来,中午闲着在床上看了几页的《大道至简》,感觉很有意思,但是电子版看起来不是很舒服,然后就睡了一会,下午就开始慢慢把做过的pta整理到报告中,先扩充了目录,让......
  • 【学习笔记】DP 优化 1
    矩阵快速幂优化DP用矩阵描述每次转移时DP数组的线性变换,如果每次变换转移相同,可以根据矩阵乘法的结合律先快速幂计算出总的转移矩阵。这里矩阵乘法不只是\((+,\times)\),实际上只要\((\oplus,\otimes)\)满足\(\otimes\)对\(\oplus\)有分配律,\(\otimes\)有结合律,\(\opl......
  • 【学习笔记】狄利克雷卷积与高级筛法
    狄利克雷卷积概念对于数论函数\(f,g\),定义其狄利克雷卷积\(h=f*g\),满足:\[h(n)=(f*g)(n)=\sum_{d\midn}f(d)g\left(\dfrac{n}{d}\right)\]运算律:满足交换律,显然具有对称性。满足结合律,等价于三个\(d_i\)贡献到\(n\)。满足加法的分配率。常见数论函数:\(\m......
  • 【学习笔记】狄利克雷卷积与高级筛法
    狄利克雷卷积概念对于数论函数\(f,g\),定义其狄利克雷卷积\(h=f*g\),满足:\[h(n)=(f*g)(n)=\sum_{d\midn}f(d)g\left(\dfrac{n}{d}\right)\]运算律:满足交换律,显然具有对称性。满足结合律,等价于三个\(d_i\)贡献到\(n\)。满足加法的分配率。常见数论函数:\(\m......
  • 第二周第二天进度总结
    2023年7月3日,今天我Java基础学到了P16-标识符,Javaweb学到了P9-HTML基本标签-超链接标签。天梯赛写到了L1-025,英语每日任务已经完成,准备新增一个任务,我打算每周二周四进行写作练习。昨天读物也看了16页,今天继续保持。同时,我已经下载并安装EclipseForJavaDeveloper,并在Eclipse中......
  • 在Jupyter笔记本中使用Python与GPT-4进行交互
    在这篇文章中,我们将讨论如何在Jupyter笔记本中使用Python与GPT-4(一种强大的自然语言处理模型)结合进行处理。尽管OpenAI并未特地发布名为"GPT-4"的模型,但我们可以使用现有的GPT-3作为参考。如OpenAI未来发布了GPT-4,其与GPT-3的用法将会非常相似。在Jupyter笔记本中使用Python与GPT......