二維前綴和詳解

咱們講一下什麼是二維前綴和,創建在一維前綴和之上,咱們要求一個矩陣內一個任意的子矩陣的數的和,咱們就能夠用二維前綴和,咱們仍是用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],怎麼來的呢?咱們畫一下圖就知道了。ios

404

這張圖就知道了(i,j)能夠由(i-1,j)(i,j-1)兩塊構成,不過要注意兩個點spa

  1. 有一塊矩陣咱們重複加了,也就是(i-1,j-1)這一塊,因此咱們要減去它.net

  2. 咱們這個矩陣是不完整的,由圖可知咱們還有一塊深藍色的沒有加,也就是(i,j)這一點,因此咱們要再加上map[i][j]也就是題目給出的矩陣中這一格的數。3d

這樣咱們就預處理完了,如今講一下怎麼經過咱們的預處理從而快速地得出咱們想要的任意子矩陣中的和,咱們定義(x1,y1)爲咱們想要子矩陣的左上角,(x2,y2)爲咱們想要子矩陣的右下角,而後咱們畫圖想想。code

404

咱們能夠經過DP[x2][y2]來計算,咱們經過圖能夠發現這個距離咱們要的還差紅色的部分看看怎麼表示紅色部分?咱們能夠分割成兩塊,分別是DP[x1][y2]DP[x2][y1]咱們發現有一塊重複減了,因此咱們再加上它即DP[x1][y1]blog

有一點注意,由於畫圖和定義緣由咱們發現邊界好像不對,咱們來看看,咱們定義的狀態是整個矩陣包括邊的和,而咱們要求的也是要包括邊的,因此咱們要再改一下,把DP[x1][y2]DP[x2][y1]DP[x1][y1]分別改爲DP[x1-1][y2]DP[x2][y1-1]DP[x1-1][y1-1]ci

這樣一減咱們就能夠獲得本身想要的答案,整理可得公式,DP[x2][y2]-DP[x1-1][y2]-DP[x2][y1-1]+DP[x1-1][y1-1]這樣咱們就能夠作到O(1)以內查詢,很奇妙吧,咱們看一下實現代碼:get

#include<iostream>
#include<cstring>
using 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 <<(dp[x2][y2]+dp[x1-1][y1-1]-dp[x1-1][y2]-dp[x2][y1-1])<<endl;//O(1)查詢 
    }
    return 0;
}

參考博文:https://blog.csdn.net/qq_34990731/article/details/82807870string

相關文章
相關標籤/搜索