前綴和與差分

前綴和
其實能夠把它理解爲數學上的數列的前n項和(對於一個一維數組的前綴和)。
咱們定義對於一個數組a的前綴和數組s,s[i] = a[1]+a[2]+...+a[i].
 
二維前綴和
與一維前綴和相似,設s[i][j]表示全部a[i'][j']的和。(1≤i'≤i,1≤j'≤j)
有一點像「矩形的面積」那樣,把一整塊區域的值都加起來。
 
前綴和的用途
通常用來求區間和。
對於一維狀況,如今我給出一個數列a,要求你回答m次詢問,每次詢問下標j到k的和。樸素的作法顯然是對於每次詢問都執行一次相加操做,而後輸出結果。這樣作是正確的,可是當m過大時就會致使計算次數過多而有可能超時。
超時的緣由一目瞭然,重複計算。那麼咱們應該怎麼改進這個方法呢?想象一下,咱們若是先提早算好了每個位置的前綴和,而後用s[k]-s[j],結果不就是咱們此次詢問的答案嗎?這樣便會使計算量大大減少。
對於二維的區間和,也是相似的。
 
咱們藉助這個圖片研究一下。假設在這個矩陣(二維數組)中,咱們要求和的是上圖中紅色區域。如今咱們已經預處理出了全部點的前綴和,如今給定兩個點(x1,y1),(x2,y2),咱們要求 以這兩個點連線爲對角線的一個子矩陣的數值之和。暴力作法直接挨個加這個我就再也不多說了,反正遲早都得TLE,咱們重點考慮用前綴和的快速作法。
首先咱們能夠把s[x2][y2]求出來,它表明整個大矩形的前綴和,而後咱們分別減去它左邊多出來的一塊的前綴和和下邊多出來一塊的前綴和,這樣就是最終答案了?
不是!這不是最終答案。能夠發現,在咱們剪掉這兩個多出的區域時,下邊的一小塊被減了兩次,但減兩次顯然是不合理的,咱們應該加回來。。
因此對於一次的查詢答案ans應該等於 s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]
這個二維前綴和也稱差分序列。
 
用差分實現區間操做
給定一個長度爲n的數列a,要求支持操做add(L,R,k)表示對a[L]~a[R]的每一個數都加上k。並求修改後的序列a。
暴力作法顯然,TLE,下一個。
咱們考慮用差分的作法。這裏 須要一個輔助數組c,c用來記錄某一個位置上的總改變量。c[i]表示的是i~n這些元素都加上c[i]這個數。咱們對[L,R]區間進行加值操做,在c[L]處加一個k,在c[R+1]處就減去一個k。最後求序列的每一個位置變成了多少,只須要求一下c數組的前綴和,而後和原數組按位相加就好。
這個結論的證實我不是太會。。呃記住它是對的就好啦。。
對於二維的狀況,一個n*m的矩陣,要求支持操做add(x1,y1,x2,y2,a),表示對於以(x1,y1)爲左下角,(x2,y2)爲右上角的矩形區域,每一個元素都加上a。要求修改後的矩陣。
咱們的作法和一維相似。用數組c存儲總改變量。在c[x1][y1]處加上a,在c[x2+1][y1]和c[x1][y2+1]處減a,在c[x2+1][y2+1]再加上a。最後(i,k)位置上的數值就是c數組在(i,k)位置的前綴和。
 
差分
用差分實現區間操做

取C數組爲修改數組,C[i]表示的是i~n這些元素都加上C[i]這個數
樣例:
ADD(1,3,1)
ADD(2,4,4)
ADD(3,7,3)
咱們對[L,R]區間進行加value操做,在C[L]處加上value,在C[R+1]處減去value
最後求序列的每一個位置變成了多少,只要看一下這個位置上C的前綴和就能夠ios

升級版:對於一個n*m的表格,要求支持操做ADD(x1,y1,x2,y2,a),表示對於以(x1,y1)爲左下角,(x2,y2)爲右上角的矩形區域,每一個元素都加上a。問最後的表格的樣子
和一維版的作法相似。
用數組C存修改信息。在C[x1][y1]處加上a,在C[x2+1][y1]和C[x1][y2+1]處減a,在C[x2+1][y2+1]再加上a。
最後(i,k)位置上的數值就是C數組在(i,k)位置的前綴和。
樹狀數組區間修改單點查詢的時候要用!數組

 

上述知識點爲我在網上dalao博主找的較好的解釋!spa

 

我本身對用差分對區間操做的理解,咱們對[L,R]區間進行加value操做,在C[L]處加上value,在C[R+1]處減去value,由於最後要用c數組的前綴和與原始數組分別相加,因此在C[L]處加上value只對L之後數有影響,在L之後的前綴和都加上了value,由於要求的做用範圍是[L,R],因此R之後的前綴和不能產生影響,則應該在C[R+1]處減去value,以與前面加的value相抵消。二維數組同理。code

下面是我遇到的例題:orm

上交大OJ 1002:二哥種花生xml

Description

二哥在本身的後花園裏種了一些花生,也快到了收穫的時候了。這片花生地是一個長度爲L、寬度爲W的矩形,每一個單位面積上花生產量都是獨立的。他想知道,對於某個指定的區域大小,在這麼大的矩形區域內,花生的產量最大會是多少。blog

Input Format

第1行有2個整數,長度L和寬度W。圖片

第2行至第L+1行,每行有W個整數,分別表示對應的單位面積上的花生產量A( 0≤A<10 )。ip

第L+2行有2個整數,分別是指定的區域大小的長度a和寬度b。ci

Output Format

輸出一個整數m,表示在指定大小的區域內,花生最大產量爲m。

Sample Input

4 5
1 2 3 4 5
6 7 8 0 0
0 9 2 2 3
3 0 0 0 1
3 3

Sample Output

38

樣例解釋

左上角:38 = (1+2+3) + (6+7+8) + (0+9+2)

數據範圍

對於30%的數據: 1≤L,W≤100;

對於100%的數據: 1≤L,W≤1000。

所有區域大小知足:1≤a≤L,1≤b≤W 。

 

分析:這裏就用到前綴和來求解遍歷,以防超時!

AC code:

 1 #include <iostream>
 2 using namespace std;
 3 const int maxn = 1000 + 5;
 4 int c[maxn][maxn] = {0};
 5 int main() {
 6     int L, W;
 7     cin >> L >> W;
 8     for(int i = 1; i <= L; i++)
 9         for(int j = 1; j <= W; j++) {
10             cin >> c[i][j];
11             c[i][j] = c[i][j] + c[i][j-1] + c[i-1][j] - c[i-1][j-1];      //求前綴和
12         }
13 
14     int a, b;
15     long max=0, sum;
16     cin >> a >> b;
17     
18     for( int i = 1; i <= L - a + 1; i++) {
19         for(int j = 1; j <= W - b + 1; j++) {
20             sum = c[i+a-1][j+b-1] - c[i-1][j+b-1] - c[i+a-1][j-1] + c[i-1][j-1];
21             if(sum > max)
22                 max = sum;
23         }
24     }
25     cout << max;
26     return 0;
27 }

 

相關文章
相關標籤/搜索