字首和 差分詳解及經典例題補充

2022-09-10 04:36:11 字數 3457 閱讀 1799

目錄

字首和 與 差分可以理解為互逆的 , 求字首和 跟 差分通常設陣列首項下標為1,方便思考的計算。

對於一維陣列 a[n] , 存在陣列 sum[n],使得 sum[i] = a[1] + a[2] + ... + a[i]

以o(1)的時間複雜度得到某塊區間的總和

舉個例子:

輸入乙個長度為 n 的整數序列。

接下來再輸入 m 個詢問,每個詢問輸入一對 l,r。

對於每個詢問,輸出原序列中從第 l 個數到第 r 個數的和。

常規演算法 是兩遍for迴圈求區間和,題目範圍小還可以接受,若是開到1e5+,必然會爆int的。所以這裡使用字首和讓時間複雜度降到o(1)

一維字首和相對較簡單,不做過多介紹

如果陣列變成二維陣列又該怎麼做呢,做法與一維字首和相類似,只是多了個容斥原理

如果我們要求給定座標的字首和,如圖

若果我們要求(3,3)的字首和 , 先算出(3,2),(2,3)的和,再減去圖中紅綠交匯的部分即(2,2) ,再加上座標(3,3)的數值,就可以求出(3,3)的和

因此,二維字首和公式:s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] +a[i][j]

那麼怎麼求任意矩陣任意位置座標的和呢

比如

我們要求(x1,y1)到(x2,y2)字首和,那麼就是求圖中紅色區域,那麼用(x2,y2)的字首和(3*3矩陣)- 綠色區域 - 藍色區間 + 綠蘭交匯區域

因此,求任意區域的字首和公式也很容易得出:

很典型的二維字首模板題

思路 : 先求字首和 , 再利用公式ans = s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1]求出答案即可

**如下

# include using namespace std ; 

const int n = 1e3 + 10 ;

int a[n][n];

int sum[n][n];

int main()

while (t --)

for (int i = 1 ; i <= n ; i++)

return 0 ;

}

二維差分和二維字首和都運用到了容斥原理

同樣,a陣列是b陣列的字首和陣列,那麼b是a的差分陣列。

那麼a陣列中a[i][j]是b陣列左上角(1,1)到右下角(i,j)所包圍矩形元素的和。

如何構造二維差分陣列

對於差分,我們始終要記住,b[i][j]的改變會影響a[i][j]及其之後的元素。

若b陣列已經構造好,讓指定區域的元素加上c

b[x1][y1] + = c;

b[x1][y2+1] - = c;

b[x2+1][y1] - = c;

b[x2+1][y2+1] + = c;

我們畫個圖來理解一下

比如我們要改變的區間是在(x1,y1)到(x2,y2)

首先對b[x1][y1]+c ,就是圖中紅色區域。

再對綠色和紫色區域操作: b[x1][y2+1] - c ,b[x2+1][y1] - c.

又因為粉色重疊部分多減了一次,再加上 b[x2+1][y2+1] + c。

再詳細分析一下

我們要求這個區域:

必然先要求這個區域:

再求這兩個區域:

最後減去交匯的區域

我們對原始陣列進行區域增減,實際上就是對b陣列的增減,通過這個方法創造差分陣列。

方法:

for(int i=1;i<=n;i++)

for(int j=1;j<=m;j++)

就等同於對原始陣列進行修改

for (int i = 1 ; i <= n ; i ++)

for (int j = 1; j <= m ; j ++)

a[i][j] += c;

假設a,b陣列均為空,實際上不為空。我們每次讓以(i,j)為左上角到以(i,j)為右上角面積內元素(其實就是乙個小方格的面積)去插入 c=a[i][j],等價於原陣列a中(i,j) 到(i,j)範圍內 加上了 a[i][j] ,因此執行n*m次插入操作,就成功構建了差分b陣列.

和上面講的思路完全一樣,直接上**

#include using namespace std;

const int n = 1000 + 10;

int a[n][n];

int b[n][n];

int n, m, q;

void insert(int x1, int y1, int x2, int y2, int c)

int main()

}while(q--)

for(int i = 1; i <= n; i++)

}for(int i = 1; i <= n; i++)

printf("\n");

}return 0;

}注意a是b的字首和, b[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1],移項就能求出a[i][j]。

差分及字首和基礎和例題總結

差分 字首和有著特殊的關係,也是一種入門演算法 首先考慮這樣乙個問題 有 n 個的正整數放到陣列 a 裡,現在要求乙個新的陣列 b,新陣列的第 i 個數 b i 是原陣列 a 第 0 到第 i 個數的和。字首和想必大家都知道,給定一陣列c i 用另外一陣列sum n 來儲存c 1 c n 的和,這樣...

字首和與差分 演算法詳解

1 字首和 其實可以把它理解為數學上的數列的前n項和 對於乙個一維陣列的字首和 我們定義對於乙個陣列a的字首和陣列s,s i a 1 a 2 a i 2 二維字首和 與一維字首和類似,設s i j 表示所有a i j 的和。1 i i,1 j j 有一點像 矩形的面積 那樣,把一整塊區域的值都加起來...

字首和 差分

數列的字首和 sum i 表示a 1 a i 的和 用處1 求i j的和sum j sum i 1 用處2 區間修改。設定乙個change陣列。當區間 i,j 上要加k時,我們令change i k,令change j 1 k。如果我們對change陣列求字首和的話,字首和sum change i ...