在学习本篇内容前建议先学习一下“一维前缀和”
一维前缀和 算法https://blog.csdn.net/czt230610/article/details/148012923?fromshare=blogdetail&sharetype=blogdetail&sharerId=148012923&sharerefer=PC&sharesource=czt230610&sharefrom=from_link接下来我们就直接从题引入
如果一维的话,很容易想到创建“前缀和”数组进行相减,但到了二维,我们要在每一行、每一列都要创建一个“前缀和”数组吗?显然太麻烦了,我们用一下数学思维或许使这个问题更加简单化。所以本题的暴力解我们就不多说了。
根据我们的算法原理:创建前缀和数组并使用,我们要“更便利“地创建这个数组。
首先,这个数组的含义是不能变的,dp[i][j]记录的是从[1,1]到dp[i,j]的所有和(为什么下标从1开始在一维模板中有说明),现在我们求dp[i][j]
根据题意,就是把图中arr的ABCD中所有元素求和即可(D就是arr[i][j]),如果我们直接求A+B+C+D,发现还是很麻烦,我们可以采用,(A+C)+(A+B)+D-A的方式,换成代码就是dp[i][j-1]+dp[i-1][j]+arr[i][j]-dp[i-1][j-1],这就是前缀和数组的预处理。
接下来是使用
上图是arr数组,我们要求出[x1,y1]-[x2,y2]之间的和(图中的D),我们可以用A+B+C+D-(A+B)-(A+C)+A.即dp[x2,y2]-dp[x1-1,y2]-dp[x2,y1-1]+dp[x1-1,y1-1]。这里的坐标-1用一下3×3表格模拟即可得出原因。
现在我们可以写题解(模板)了
#include <iostream>using namespace std;
#include <vector>int main()
{//输入数据int n=0,m=0,q=0;cin>>n>>m>>q;vector<vector<int>> arr(n+1,vector<int>(m+1));for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>arr[i][j];
//预处理前缀和数组vector<vector<long long>> dp(n+1,vector<long long>(m+1));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]+arr[i][j];//使用int x1=0=,y1=0,x2=0,y2=0;while(q--){cin >>x1>>y1>>x2>>y2;cout<<dp[x2][y2]-dp[x2,y1-1]-dp[x1-1,y2]+dp[x1-1,y1-1]<<endl;}return 0;
}