前缀和
前缀和是一种重要的预处理,能大大降低查询的时间复杂度。
最简单的一道题就是给定 n 个数和 m 次询问,每次询问一段区间的和。求一个 O(n + m) 的做法。
用 O(n) 前缀和预处理,O(m) 询问。
一、一维前缀和
主要代码
for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i]; //O(n) while(m--) //O(m) { int L, R; scanf("%d%d", &L, &R); printf("%d\n", sum[R] - sum[L - 1]); }
二、二维前缀和
给定一个n*n的矩阵,找一个最大的子矩阵,使得这个子矩阵里面的元素和最大。
这道题最朴素的算法是 O(n6),用二维前缀和可以降到 O(n4)。
再想想前缀和矩阵怎么生成?看个图就明白了:
那么最大的矩形前缀和就等于蓝的矩阵加上绿的矩阵,再减去重叠面积,最后加上小方块,即
sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j]
主要代码
for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) sum[i][j] = sum[i - 1][j] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j]; for(int i = 1; i <= n; ++i) //枚举矩阵左右端点 for(int j= 1; j <= n; ++j) for(int k = i; K <= n; ++k) for(int h = j; h <= n; ++h) { tot = sum[k][h] - sum[i - 1][h] - sum[k][j - 1] + sum[i - 1][j - 1]; //同理矩阵生成 ans = max(ans, tot); }
B3612 【深进1.例1】求区间和
P4702 取石子(入门) 前缀和
P5638 【CSGRound2】光骓者的荣耀(普及-) 前缀和
P1147 连续自然数和(普及-) 枚举,前缀和,数学公式