我們講一下什麼是二維字首和,建立在一維字首和之上,我們要求乙個矩陣內乙個任意的子矩陣的數的和,我們就可以用二維字首和,我們還是用dp來預處理,狀態和一維字首和差不多,只不過我們多加了一維,dp[i][j]
表示(1,1)
這個點與(i,j)
這個點兩個點分別為左上角和右下角所組成的矩陣內的數的和,好好想一下狀態轉移方程,dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+map[i][j]
,怎麼來的呢?我們畫一下圖就知道了。
這張圖就知道了(i,j)
可以由(i-1,j)
和(i,j-1)
兩塊構成,不過要注意兩個點
有一塊矩陣我們重複加了,也就是(i-1,j-1)
這一塊,所以我們要減去它。
我們這個矩陣是不完整的,由圖可知我們還有一塊深藍色的沒有加,也就是(i,j)
這一點,所以我們要再加上map[i][j]
也就是題目給出的矩陣中這一格的數。
這樣我們就預處理完了,現在講一下怎麼通過我們的預處理從而快速地得出我們想要的任意子矩陣中的和,我們定義(x1,y1)
為我們想要子矩陣的左上角,(x2,y2)
為我們想要子矩陣的右下角,然後我們畫圖想一想。
我們可以通過dp[x2][y2]
來計算,我們通過圖可以發現這個距離我們要的還差紅色的部分看看怎麼表示紅色部分?我們可以分割成兩塊,分別是dp[x1][y2]
和dp[x2][y1]
我們發現有一塊重複減了,所以我們再加上它即dp[x1][y1]
。
有一點注意,因為畫圖和定義原因我們發現邊界好像不對,我們來看看,我們定義的狀態是整個矩陣包括邊的和,而我們要求的也是要包括邊的,所以我們要再改一下,把dp[x1][y2]
和dp[x2][y1]
和dp[x1][y1]
分別改成dp[x1-1][y2]
和dp[x2][y1-1]
和dp[x1-1][y1-1]
這樣一減我們就可以得到自己想要的答案,整理可得公式,dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1]
這樣我們就可以做到o(1)
之內查詢,很奇妙吧,我們看一下實現**:
#include#includeusing namespace std;
int dp[2000][2000],map[2000][2000];
int main()
{ int m,n,k;//所給的矩陣是n*m的,有k組查詢
cin >>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >>map[i][j];
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)//預處理一波
for(int j=1;j<=m;j++)
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+map[i][j];
for(int i=1;i<=k;i++)//接受查詢
{ int x1,x2,y1,y2;
cin >>x1>>y1>>x2>>y2;
cout <
二維字首和
時間限制 1 sec 記憶體限制 128 mb 提交 155 解決 51 提交 狀態 討論版 命題人 admin 題目描述 一種新型的雷射炸彈,可以摧毀乙個邊長為r的正方形內的所有的目標。現在地圖上有n n 10000 個目標,用整數xi,yi 0 xi,yi 5000 表示目標在地圖上的位置,每個...
二維字首和
1 二維字首和 模板 二維字首和 模板題 acwing 796.子矩陣的和 s i,j 第i行j列格仔左上部分所有元素的和 1.以 x1,y1 為左上角,x2,y2 為右下角的子矩陣的和為 s x2 y2 s x1 1 y2 s x2 y1 1 s x1 1 y1 1 s x y s x y 1 s...
二維字首和
直接看乙個例子 假設給定乙個矩陣 1 2 4 3 5 1 2 4 6 3 5 9 那麼,可以推出他的二維字首和矩陣為 1 3 7 10 691522 121829 45 在二維字首和陣列中,9 1 2 5 1 15 1 2 5 1 4 2 18 1 5 6 2 1 3 即二位字首和陣列中第 i 行第...