字首和與差分(溫故知新)
阿新 • • 發佈:2020-09-23
所謂字首和就是前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++) { 12cin >> 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.求出區間和,反推原陣列