字首和,差分演算法

2021-10-05 14:16:25 字數 2922 閱讀 9951

其實可以把它理解為數學上的數列的前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個元素的數列d,建立記錄它每項與前一項差值的差分陣列f:顯然,f[1]=d[1]-0=d[1];對於整數i∈[2,n],我們讓f[i]=d[i]-d[i-1]。//f[i]陣列為差分陣列,d[i]陣列為原陣列

對數列區間[l,r]中的每個數加上x,第乙個受影響的差分陣列中的元素為f[l],即令f[l]+=x,那麼後面數列元素在計算過程中都會加上x;

最後乙個受影響的差分陣列中的元素為f[r],所以令f[r+1]-=x,即可保證不會影響到r以後數列元素的計算。

這樣我們不必對區間內每乙個數進行處理,只需處理兩個差分後的數即可.

差分與字首和互逆,求完差分後可以求字首和得到修改後的資料

for

(int i=

1;i<=n;i++

)d[i]

+=d[i-1]

,a[i]

=a[i-1]

+d[i]

;

d. constant palindrome sum

question

給定乙個長度為 n的數列,n 為偶數,保證每個元素在 [1,k] 之間。

每次操作可以把某個位置的數字變成 [1,k] 內的任意數字。

要求讓這個數列滿足:對於所有的i∈[1,n/2],a[i]+a[n−i+1]均相等為res。

求最少的操作次數。

solution

差分維護修改次數

為了下列表述簡單方便、簡潔,設

l=min(a[i],a[n−i+1])+1

r=max(a[i],a[n−i+1])+k

1.修改次數為0:res=a[i]+a[n−i+1]

2.修改次數為1:res∈[l,r] and res≠a[i]+a[n−i+1]

3.修改次數為2:res∈[2,l-1]∪[r+1,2k]

直接暴力是o(mn),考慮優化利用差分陣列維護答案為[2,2*k]時的修改次數。

#include

using

namespace std;

const

int n=

1e6+10;

int a[n]

,d[n]

;int t,n,k;

intmain()

for(

int i=

0;i<=

2*k;i++

)d[i]=0

;int l,r;

for(

int i=

1;i<=n/

2;i++

)int ans=

1e9;

for(

int i=

1;i<=

2*k;i++

) cout<

}return0;

}

我們先假設所有的操作都是i和n-i+1也就是2,那麼對於每一對a[i]+a[i-1]來說,l=min(a[i],a[n-i+1])+1,r=max(a[i],a[n-i+1])+k,只要是這個區間【l,r】裡的x,a[i]和a[n-i+1]都只要選乙個來操作就可以了,同時對於x==a[i]+a[n-i+1]來說就不需要操作了,用差分維護一下,最後看那個x的次數最小。

字首和 差分

數列的字首和 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 ...

字首和 差分

有n個數和q次操作,每一次操作指明了要操作的區間 l,r 以及讓該區間內的所有元素全部加c 輸出q次操作後所有元素的大小 第一行 n q 1 n,q 2 105 第二行 n個數 a1,a2 an 106 ai 106 接下來q 行 每行3個數 l r c 表示 l,r 區間內每個數加c 1 l r ...

字首和 差分

顧名思義 用某乙個陣列來記錄陣列a前i項和,這個還可以用來求區間 l,r 的和 s r s l 1 因為第l項也在區間內 話不多說,直接上例題 leetcode 5393 ac const int maxn 1e5 5 class solution int ans 0 for int i 0 i k...