二维前缀和


之前我们说过

今天我们来看看二维前缀和

二维前缀和要比一维前缀和难一些


二维前缀和


概念

如图,一个 n*m 的矩阵,

标黑的点是 (那么 (前缀和)为框起的红色部分之和

如果在一矩形中,有一点 (i,j)

s即为矩形左上角的点到 所有数之和


如何求二维前缀和

思路

我们不难发现, s[i-1][j]s[i][j-i] 有重叠部分(即红色部分)

得出的即为红色部分加上黄色部分加上蓝色部分的和

最后再加上绿色部分 a[i][j] (即这个数本身)

即为 s[i][j]

(你可以理解为小学的容斥原理)

我们可以推出其递推式:

 s[i-1,j]+ s[i,j-1]-s[i-1,j-1]+A[i,j]

代码实现

#include

using namespace std;

int sum[900][900],n,m,a[900][900];

int main()
{
    scanf ("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        {
            scanf ("%d",a[i][j]);//输入
            
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];//递推式
        }
    }
    
    for (int i=1;i<=n;++i)
    {
        for (int j=1;j<=m;++j)
        {
            printf ("%d",sum[i][j]);//输出
        }
        printf ("\n");
    }
    
    return 0;
}

子矩阵求和

二维前缀和的用处就是求子矩阵区间和

对于一个 n*m 的矩阵

如果我们知道其右下点坐标 (i,j)

就可以求出另外3点的坐标:(i-n,j) , (i,j-m) , (i-n,j-m)

然后再来一个容斥就可以求它的区间和

我们有:

 A[x,y]=S[i,j]-S[i-n,j]-S[i,j-m]+S[i-n,j-m]


例题

仍然来看一道题

标签:前缀和  (因为不会dp,所以选择暴力) 用二维前缀和预处理一下 枚举左上点的坐标 (i,j) 再枚举一下边长 如果枚举的这个矩阵的区间和等于 r,则证明该区间内每个元素都是 1 ,符合要求 优化: 如果枚举的这个矩阵的区间和不等于 r,可以直接 break  ,因为后来枚举的大矩阵肯定包含此含有 0 的小矩阵,导致大矩阵也含有 0    AC code
#include

using namespace std;

int n,m,sum[150][150],s,a,maxn;

int max (const int &a,const int &b)
{
    return a>b?a:b;
}
int min (const int &a,const int &b)
{
    return a

END