前缀和思想
前缀和的定义:
对于一个数组 a [i], 定义一个数组 sum [i], 其中 sum [0]=0, sum [i]=(a [1]+a [2]+…+a [i]), 则 sum 称为 a 的前缀和
前缀和的作用:
对于无修改数组的查询区间和,可以在边读入数据时边处理前缀和, 然后在 O(1) 的时间下回答每个询问,预处理 O (n). 具体做法就是求出前缀和后对于询问 [l,r] 的区间和直接计算 sum [r]-sum [l-1].
1 | int n,m; |
下面拿今天做的题目举个例子:
给出一个只包含 0 和 1 的字符串,可以将某一位上的数取反 (即 0 变成 1, 1 变成 0), 要使得最后得到的串中所有 0 都在 1 的前面, 至少要几次取反?
样例:输入:010001 输出:1
可以考虑枚举最后得到串中 0 串的长度,在这个长度前面的所有 1 变成 0, 后面的所有 0 变成 1, 每次更新最少改变次数
用前缀和预处理串中某个位置 i 之前的 0/1 的个数 , 记为 S0 和 S1, 则 0 串长度为 i 的改变次数为 S1 [i]+S0 [n]-S0 [i-1](0<=i<=n)
时间复杂度 O (n), 原数据范围为 n<=1e5, 完全可过
从暴力枚举 0/1 个数的 O (n^2) 到 O (n) 是个不小的优化, 所以说前缀和思想是个很有用的优化思路
二维前缀和
相比于一维的前缀和,二维前缀和多了一维,处理起来稍微麻烦一点
对于一个二维数组 a [i][j], 设 sum [i][j]=(a [1][1]+a [1][2]+…+a [1][j]+a [2][1]+…+a [2][j]+…+a [i][j]), 则 sum [i][j] 为 a [i][j] 的二维前缀和
可以根据容斥原理来处理二维前缀和
对于 sum [i][j], 有 sum [i][j]=sum [i-1][j]+sum [i][j-1]-sum [i-1][j-1]
二维区间和 w (x1,y1,x2,y2)=sum [x2][y2]-sum [x2][y1]-sum [x1][y2]+sum [x1][y1]