前缀和
一维
求[l,r]的和,s[r] - s[l - 1]
下标从1开始,否则求[1,r]的和,需要特判
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 + 10];
int[] s = new int[n + 10];
for(int i = 1; i <= n; i ++)
a[i] = in.nextInt();
for(int i = 1; i <= n; i ++)
s[i] = s[i - 1] + a[i];
for(int i = 0; i < m; i ++) {
int l = in.nextInt();
int r = in.nextInt();
System.out.println(s[r] - s[l - 1]);
}
}
}
二维
s[2][3]已经把a[2][3]之前的数字加起来了,s[3][2]同理
需要减去重复的s[2][2]再加上原本的a[3][3]就是s[3][3]
s[i, j] = 第 i 行 j 列格子左上部分所有元素的和
s[i] [j] = s[i-1][j] + s[i][j-1] - s[i-1][ j-1] + a[i] [j]
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
s[x2, y2] - s[x1-1, y2] - s[x2, y1-1] + s[x1-1, y1-1]
差分
一维
s[i] = s[i - 1] + a[i]
a[i] = s[i] - s[i - 1]
输入数组a,求差分数组b,再次求前缀和
public class Main {
private static final int N = 100010;
private static final int[] a = new int[N + 5];
private static final int[] b = new int[N + 5];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
for(int i = 1; i <= n; i ++) {
a[i] = in.nextInt();
//a[]是b[]的前缀和
b[i] = a[i] - a[i - 1];
}
while (m-- > 0) {
int left = in.nextInt();
int right = in.nextInt();
int c = in.nextInt();
difference(left, right, c);
}
for (int i = 1; i <= n; i++) {
b[i] += b[i - 1];
System.out.print(b[i] + " ");
}
}
private static void difference(int left, int right, int c) {
b[left] += c;
b[right + 1] -= c;
}
}
求差分数组
private static void insert(int left, int right, int c) {
b[left] += c;
b[right + 1] -= c;
}
每次添加一个数,根据图可以看出使用insert能直接得出差分数组,所以有另一种写法
s[] = {1,3,6,10}
s[1] = a[1] s[2] = a[1] + a[2] s[3] = a[1] + a[2] + a[3]求差分数组a,那么每次插入s的数字要进行一次insert操作,就不影响后面的数
a[1] = s[1] a[2] = s[2] - a[1] a[3] = s[3] - s[2]输入不能写入a[i],赋值给t(是前缀和数组中的值),然后通过t得到差分数组
public class Main {
private static final int N = 100010;
private static final int[] a = new int[N + 5];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
for(int i = 1; i <= n; i ++) {
int t = in.nextInt();
insert(i,i,t);
}
while (m-- > 0) {
int left = in.nextInt();
int right = in.nextInt();
int c = in.nextInt();
insert(left, right, c);
}
for (int i = 1; i <= n; i++) {
a[i] += a[i - 1];
System.out.print(a[i] + " ");
}
}
private static void insert(int left, int right, int c) {
a[left] += c;
a[right + 1] -= c;
}
}
二维
b[i] [j] = b[i-1][j] + b[i][j-1 ] - b[i-1][ j-1] + a[i] [j]
a[i][j] = b[i][j] - b[i-1][j] - b[i][j-1] + b[i-1][j-1];
输入的数字已经是前缀和数组中的值,求二维差分数组,根据图可以得出结论
void insert(int x1, int y1, int x2, int y2, int c)
{
a[x1][y1] += c;
a[x2 + 1][y1] -= c;
a[x1][y2 + 1] -= c;
a[x2 + 1][y2 + 1] += c;
}
import java.io.IOException;
import java.util.Scanner;
import java.util.stream.IntStream;
public class Main {
private static final int N = 1010;
private static final int[][] a = new int[N + 5][N + 5];
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int q = in.nextInt();
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) {
int t = in.nextInt();
insert(i,j,i,j,t);
}
while(q -- > 0) {
int x1 = in.nextInt();
int y1 = in.nextInt();
int x2 = in.nextInt();
int y2 = in.nextInt();
int c = in.nextInt();
insert(x1,y1,x2,y2,c);
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
a[i][j] += a[i][j - 1] + a[i - 1][j] - a[i - 1][j - 1];
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
private static void insert(int x1, int y1, int x2, int y2, int c) {
a[x1][y1] += c;
a[x2 + 1][y1] -= c;
a[x1][y2 + 1] -= c;
a[x2 + 1][y2 + 1] += c;
}
}