【算法競賽刷題模板15】【二維數組前綴和】
0.總結
Get to the points first. The article comes from LawsonAbs!
- 二維數組前綴和
- 容斥原理
下面結合一道例題【洛谷】P2280 [HNOI2003]激光炸彈,來講講如何實現二維數組的前綴和。
1.題意
二維座標中每個點都有一定的價值。求出座標系中以某點作爲邊長m的正方形的右下角的最大價值。
2.思想
二維數組前綴和
- 這裏的前綴指的是從
(0,0)
到(x,y)
這個矩形區域,其和就是s[x][y]
- 前綴和的推導公式
s[i][j] = s[i-1][j] + s[i][j-1]- s[i-1][j-1] + val[i][j]
,其中s[0][j]
和s[i][0]
需要單獨判斷
如果用圖形表示的話,則是下面這個樣子
s[i][j] =
s[i][j] =
s[i-1][j] =
s[i-1][j-1]=
val[i][j]=
綜合表述,也就是下面這個樣子:
棕色是綠色和紫色的重合部分。
- 在得到前綴和的基礎上,針對題目要求適當變形即可
3.代碼
#include<iostream>
using namespace std;
const int X = 5005,Y = 5005,N = 5005;
int s[N][N];//二維數組前綴和
int res = 0;
int main(){
int n,m;
cin >> n>> m;
int a,b,w,mx=0,my=0;
for(int i =0;i < n;i++){
cin >> a >> b >> w ;
mx=max(mx,a);//求出座標的最大值
my=max(my,b);
s[a][b]+=w;//爲節省空間,直接累加
}
//1.計算前綴和
//01.單獨計算s[0][j], s[i][0]
//02.計算s[i][j]
for(int i = 1;i<= max(mx,my);i++){
s[i][0] = s[i-1][0] + s[i][0];
s[0][i] =s[0][i-1] + s[0][i];
}
for(int i= 1;i<=max(mx,my);i++){
for(int j = 1;j<=max(mx,my);j++){
//因爲s[i][j]尚未計算過,所以可以累加
s[i][j] += s[i-1][j] + s[i][j-1] - s[i-1][j-1] ;
}
}
//2.計算m個正方形內的和,以(i,j)爲正方形的右下角
//01.如果枚舉左上角,則需要特判邊界處理,所以更優的方法是枚舉右下角
//02.注意這裏的i,j的上限是max(mx,my),否則當m>mx時,就會出現問題。
for(int i = m-1;i<=max(mx,my);i++){
for(int j = m-1;j<=max(mx,my);j++){
int temp = s[i][j]
- (j-m<0 ? 0: s[i][j-m]) //防止下標越界&簡潔,用三元運算符
- (i-m<0 ? 0: s[i-m][j])
+ ((i-m<0 || j-m<0)? 0:s[i-m][j-m]);
res = max(res,temp);
}
}
cout << res <<"\n";
}
測試用例
1 3
0 1 0
2 1
0 0 1
1 1 1
2 1
0 0 1
1 2 3
3 1
0 0 1
1 2 3
0 1 4
3 2
0 0 1
1 2 3
0 1 4