二維字首和詳解
阿新 • • 發佈:2018-12-11
這幾天在打比賽時遇到了二維字首和,看了一下深有體會,發一篇詳解。 首先,什麼是字首和?一個數列,我們要計算某個區間內的和,該怎麼做呢?正所謂暴力出奇跡,這一個也可以,我們暴力列舉每一個區間內的數並且相加,可是這個是O(n)的時間複雜度,不要小看這個線性,可如果在DP裡的話這相當於加了一次方,卡你非常簡單,下面講一下O(n)的預處理,O(1)的計算,你可能會說這個也是線性,有差嗎?當然有差,這個是需處理,不會像暴力一樣在DP中使DP的時間複雜度加一次方而是直接加上O(n)。下面講一下做法,字首和,顧名思義就是第幾個數之前的數的和,我們用DP來預處理,我們定義狀態DP[i]表示到第i個數(包括它)為止前面所有數的和,從而得出狀態轉移方程DP[i]=DP[i-1]+num[i],num[i]表示陣列中第i個數,這樣要計算閉區間i,j(閉區間就是指i<=x<=j,x就是區間裡的數)的和就是DP[j]-DP[i-1],這個畫圖理解如下:
#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;
}