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...