1. 程式人生 > 實用技巧 >字首和與差分(溫故知新)

字首和與差分(溫故知新)

所謂字首和就是前n個數的總和,預處理以後可以通過b[r]-b[l-1]得出由l到r的值。

1.一維字首和

比較簡單不多贅述。

程式碼:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main() {
 6     int a[100], b[100];
 7     int n, l, r;
 8     cin >> n;
 9     cin >> l >> r;
10     //打表
11     for(int i = 1; i <= n; i++) {
12
cin >> a[i]; 13 } 14 b[1] = a[1]; 15 for(int i = 2; i <= n; i++) { 16 b[i] = b[i-1] + a[i]; 17 } 18 19 for(int i = 1; i <= n; i++) { 20 cout << b[i] << " "; 21 } 22 cout << endl; 23 24 cout << b[r]-b[l-1];
25 return 0; 26 }

2.二維字首和

預處理狀態轉移方程:b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j],下圖很形象的表示出了這個式子。要求從b[x1][y1]到b[x2][y2]的和即為b[x2][y2] - b[x1-1][y2] - b[x2][y1-1] + b[x1-1][y1-1],依舊錶示如圖。

程式碼:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main() {
 6     int a[100
][100], b[100][100]; 7 int n, m, x1, x2, y1, y2; //假設x2>x1, y2> y1 8 cin >> n >> m; 9 cin >> x1 >> y1 >> x2 >> y2; //從b[x1][y1]到b[x2][y2] 10 for(int i = 1; i <= n; i++) { 11 for(int j = 1; j <= m; j++) 12 cin >> a[i][j]; 13 } 14 15 //打表 16 memset(b, 0, sizeof(b)); //這個不要忘記 17 for(int i = 1; i <= n; i++) { 18 for(int j = 1; j <= m; j++) 19 b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j]; 20 } 21 22 cout << b[x2][y2] - b[x1-1][y2] - b[x2][y1-1] + b[x1-1][y1-1]; 23 return 0; 24 }

3.差分

差分:對於數列 a,其第 i 個元素和第 i - 1 個元素的差稱為數列 a 第 i 項的差分。

表示式: b[i] = a[i] - a[i - 1]

對差分陣列求字首和就可以得到原數列a :sumb[i] = b[1] + b[2] + ... b[i] = a[1] + a[2] - a[1] + ... + a[i] - a[i - 1] = a[i]

簡單應用:對從l到r的陣列進行批量加減。

最簡單的做法就是對於修改操作逐一加上 p,對於查詢操作可以用前面的字首和來求。但這樣會t。其實我們可以拿差分陣列做文章,每次只修改差分陣列的兩個端點即可,見下面的圖解舉例:

1.先求出差分序列

2.給定區間的頭元素+p

3.給定區間的尾元素的下一個元素-p

4.求出區間和,反推原陣列

參考部落格:https://www.cnblogs.com/yxr001002/p/13353775.html

https://www.cnblogs.com/hulean/p/10824752.html