P2363题解
二维前缀和板子
首先我们根据题意来判断时间复杂度,先使用
然后我们来处理前缀和,先来制作一个二维前缀和,原理如下图所示:
如果我们现在想要求出红色矩阵数字的总和,那么我们可以将大矩阵减去两个绿色矩阵。其中我们发现蓝色矩阵被绿色矩阵覆盖了两次,因此我们要把这个矩阵给补回来,因此我们得到前缀和的式子为:
Code
#include<bits/stdc++.h>
#define ll long long
#define F(i,j,n) for(int i=j;i<=n;i++)
using namespace std;
ll n,ans;
ll a[55][55],sum[55][55];
map<ll,ll> mp;
int main(){
cin>>n;
F(i,1,n) F(j,1,n){
cin>>a[i][j];
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];//前缀和预处理
}
F(i,1,n){
F(j,1,n){
F(x,1,i) F(y,1,j) mp[sum[i][j]-sum[i][y-1]-sum[x-1][j]+sum[x-1][y-1]]++;//查询第一个矩阵的可能情况和(左上角)
F(x,i+1,n) F(y,j+1,n) ans+=mp[sum[x][y]-sum[x][j]-sum[i][y]+sum[i][j]];//查询第二个矩阵的可能情况和并加上其中的答案(右下角)
mp.clear();//清空哈希
F(x,1,i) F(y,j+1,n) mp[sum[i][y]-sum[x-1][y]-sum[i][j]+sum[x-1][j]]++;//查询第一个矩阵的可能情况和(左下角)
F(x,i+1,n) F(y,1,j) ans+=mp[sum[x][j]-sum[i][j]-sum[x][y-1]+sum[i][y-1]];//查询第二个矩阵的可能情况和并加上其中的答案(右上角)
mp.clear();//清空哈希
}
}
cout<<ans;
return 0;
}