前缀和是比较简单的知识,但如果没有学过的话,就不知道怎么运用了
一. 感受题目
这是一道经典的前缀和题目,只要学过前缀和知识就会了
这是扩展版的前缀和题目,二维数组,这个也不难,但也理解二维上前缀和为什么那么运用
二.知识讲解
- 原数组: a[1], a[2], a[3], a[4], a[5], …, a[n]
- 前缀和 Si为数组的前 i项和
- 前缀和: S[i] = a[1] + a[2] + a[3] + … + a[i]
注意: 前缀和的下标一定要从 1开始, 避免进行下标的转换
- s[0] = 0
- s[1] = a[1]
- s[2] = a[1] + a[2]
阅读以上知识,我们就知道,前缀和的作用就是快速求出某段区间的和
三.代码应用
那么在一中欣赏的第一道题目怎么运用前缀和知识去解决呢?如果硬是要用暴力解法的话就会导致超时,一些测试用例过不掉。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[] a = new int[n + 1];
long[] s = new long[n + 1];
for(int i = 1;i <= n;i ++) {
a[i] = in.nextInt();
s[i] = s[i - 1] + a[i]; // 前缀和关键
}
while(m > 0) {
m--;
int l = in.nextInt();
int r = in.nextInt();
System.out.println(s[r] - s[l - 1]);
}
}
}
那么第二道题目呢?涉及到这种二维平面的题目,我们一定要画图进行理解
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int q = in.nextInt();
int[][] a = new int[n + 1][m + 1];
long[][] s = new long[n + 1][m + 1];
for(int i = 1;i <= n;i ++) {
for(int j = 1;j <= m;j ++) {
a[i][j] = in.nextInt();
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; // 关键,画个图想下
}
}
while (q > 0) {
q--;
int x1 = in.nextInt();
int y1 = in.nextInt();
int x2 = in.nextInt();
int y2 = in.nextInt();
System.out.println(s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]); // 同理画个图
}
}
}
以上就是前缀和的知识了,接下来我们来看看差分的知识,这两个放在一起是最好的,差分的理解其实要基于前缀和的
四.感受题目
首先我们来感受一下差分的题目
五. 知识讲解
- 原数组: a[1], a[2], a[3], a[4], a[5], …, a[n]
- 前缀和 Si为数组的前 i项和
- 前缀和: S[i] = a[1] + a[2] + a[3] + … + a[i]
- 差分:a[i] = S[i] - S[i - 1] 这时候我们就把a[i]叫做s数组的差分数组,s[i]称之为a[i]的前缀和数组
所以差分的应用是在于运用在一定范围内去加减某一个数,差分的思维明显会比前缀和要绕,所以这里要注意点
六.差分的代码应用
首先是简单题
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[] a = new int[n + 1];
int[] b = new int[n + 2];
for(int i = 1;i <= n ;i ++) {
a[i] = in.nextInt();
b[i] = a[i] - a[i - 1];
}
while (m > 0) {
m--;
int l = in.nextInt();
int r = in.nextInt();
int c = in.nextInt();
b[r + 1] -= c;
b[l] += c;
}
for (int i = 1;i<= n; i++) {
a[i] = b[i] + a[i - 1];
System.out.print(a[i] + " ");
}
}
}
然后也是第二题二维平面的一个差分应用
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int q = in.nextInt();
int[][] a = new int[n + 1][m + 1];
int[][] b = new int[n + 2][m + 2];
for(int i =1 ;i <= n;i ++) {
for(int j = 1;j <= m;j ++) {
a[i][j] = in.nextInt();
b[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1];
}
}
while (q > 0) {
q--;
int x1 = in.nextInt();
int y1 = in.nextInt();
int x2 = in.nextInt();
int y2 = in.nextInt();
int c = in.nextInt();
insert(b, x1, y1, x2, y2, c);
}
for(int i =1 ;i <= n;i ++) {
for(int j = 1;j <= m;j ++) {
a[i][j] = b[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
private static void insert(int[][] b, int x1, int y1, int x2, int y2, int c) {
b[x1][y1] += c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y1] -= c;
b[x2 + 1][y2 + 1] += c;
}
}