c 字首和與差分

2021-10-06 19:24:02 字數 3160 閱讀 6483

1、簡介

字首和也是乙個在比賽中比較實用的方法,他能很快得求出乙個區間的和,速度為o(1)。

一維的字首和陣列sum[ i ]就是存的是前i個數的總和。根據這個公式我們很容易得到x到y區間的總和就是sum[ y ] - sum[ x ]。

二維的字首和如sum[ i ][ j ]是指(i,j)點的左上角的矩陣的各數總和,及0 – i行且0 – j列的和。他可以快速的求出矩陣中任何乙個子矩陣的和,如求長為l且右下角頂點為(i,j)的正方形只需sum[ i ][ j ] - sum[ i ][ j - l ] - sum[ i - l ][ j ] + sum[ i - l ][ j - l ]。

2、**模板

//1.一維的字首和

for(

int i =

1;i <= n;i++

) sum[i]

+= sum[i-1]

; ans = sum[y]

- sum[x]

;//2.二維的字首和

for(

int i =

1;i <= n;i++

)for

(int j =

1;j <= m;j++

) sum[i]

[j]+

= sum[i-1]

[j]+ sum[i]

[j-1

]- sum[i-1]

[j-1]]

;ans = sum[i]

[j]- sum[i-x]

[j]- sum[i]

[j-y]

+ sum[i-x]

[j-y]

;

3、經典例題

1.雷射炸彈

思路:用二維的字首和計算,求得矩陣的字首和後列舉所有邊長為r的情況,求出和的最大值即可。

#include

using

namespace std;

const

int n =

5010

;int f[n]

[n];

//f為求sum和的二維陣列

int n,r,h,l,x,y,w;

//n為點數,r為半徑,h l為最大的長和寬

intmain()

for(

int i =

1;i <= h;i++

)//求字首和

for(

int j =

1;j <= l;j++

) f[i]

[j]+

= f[i-1]

[j]+ f[i]

[j-1

]- f[i-1]

[j-1];

int res =0;

for(

int i = r;i <= h;i++

)//求任意矩陣的和,列舉所有邊長為r的矩陣

for(

int j = r;j <= l;j++

) res =

max(res,f[i]

[j]- f[i-r]

[j]- f[i]

[j-r]

+ f[i-r]

[j-r]);

cout << res << endl;

//res記錄最大的矩陣和即為答案

return0;

}

4、用處

快速求一維或二維陣列某區間的和

1、定義

差分就是陣列b對於陣列a有b[ 1 ] == a[ i ],b[ i ] = a[ i ] - a[ i-1 ](2 <= i <= n),b就是a的差分。

差分和字首和相反,在對陣列某區間進行操作時十分方便。

2、**模板

for

(int i =

0;i < n;i++

) cin >> a[i]

;for

(int i = n-

1;i >

0;i--

)//從後往前迴圈

a[i]

-= a[i-1]

;//差分覆蓋a陣列

3、經典例題

1.增減序列

思路:通過對區間加一減一使得陣列的各數相同,就是指使陣列的差分2-n位都變成0。對區間[ a,b ]的數加一就等於對陣列的差分b[ a ] + 1且b[ b+1 ] - 1。

有了這個性質,我們就選b[ i ]和b[ j ]對i,j區間進行加或減的操作,為了使操作次數最小我們盡量選擇一正一負作為i,j區間,這樣一邊加,一邊減使得正負都接近0,操作次數就會減少,所以最少操作次數就是差分中2-n位的所有正數和與負數和的絕對值中的最大值。對於無法修改的數可以用b[ 1 ]或者b[ n+1 ]進行修改,結果數就是對正負數配對完後剩下的數加一。

#include

#include

using

namespace std;

const

int n =

100010

;int a[n]

,n;long

long

int pos,neg;

intmain()

2、最高的牛

思路:兩頭牛能夠看見,則說明這兩頭之間的牛的身高最高為兩邊的減一,每次輸入將中間的區間減一即可,但在輸入後先判重,檢查之前是否已經減過1了,就不用再次減一了。

#include

#include

using

namespace std;

const

int n =

10010

;int f[n]

,n,p,h,m;

setint,

int>

> judge;

//set判重,將兩端點a,b壓入pair

intmain()

))//如果之前沒輸過);

//標記

f[a+1]

--;//差分陣列的性質,區間[a,b]減一

f[b]++;

}}for(

int i =

1;i <= n;i++

)return0;

}

4、用處

方便對某區間進行加減操作

字首和與差分

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

字首和與差分

從陣列第乙個開始累加 s i s i 1 a i 求區間 l,r 的和,o 1 複雜度sum s r s l 1 遞推s i j s i j s i 1 j s i j 1 s i 1 j 1 例題 雷射炸彈一種新型的雷射炸彈,可以摧毀乙個邊長為r的正方形內的所有的目標。現在地圖上有n n 1000...

字首和與差分

例題入口 include const int n 320 int a n n a i 1 a i 0 1.對a 求出平方數 將其值置為1 不是平方數就是0 2.對a求乙個字首和 3.對 a,b 求乙個部分和 int sum n n void init for int i 1 i 100000 i i...