前缀和讲解

什么是前缀和?
假如有一个数组
a[0]、a[1]、a[2]、a[3]、...、a[n]
令
s[i]=a[0]+a[1]+...+a[i]//数组前i项和=>区间[0,i]之间的所有和=>i的前缀和
此时的s就是数组的一维前缀和
前缀和是一种比较重要的预处理,它能大大的降低查询的时间复杂度
我们可以通过前缀和来求出任意区间的求和值,比如我们想求出[5,10]区间内的求和值
即s[10]-s[4]=[5,10]

现在有一道前缀和的题,我们来看看。

前缀和题

这题能如果要暴力做的话时间复杂度会很高,所以我们需要用二维前缀和和一些内存优化去做。

这就是二维数组中的一个点的前缀和:

而我们要计算(x,y)点的前缀和需要

s[x][y]=s[x-1][y]+s[x][y-1]-s[x][y]((x,y-1)和(x,y-1)的前缀和有重叠部分,所以需要加上去(x-1,y-1)的前缀和)

而如果我们想计算这个大图中红色的面积

我们可以通过二维前缀和去求

S红=s[x][y]-s[x-R-1,y]-s[x,y-R-1]+s[x-R-1][y-R-1](包括红色面积的周长)

下面是c++的代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int M=5010;
int a[M][M];

int main()
{
    int N,R,n,m,res=0;
    cin>>N>>R;
    n=R;m=R;//可能会被坑,因为有可能激光炸弹的范围比整个矩阵的面积还大,所以需要初始化一下
    for(int i=0,x,y,w;i<N;i++)
    {
        cin>>x>>y>>w;
        x++;y++;//把坐标+1的话比较好处理,不用判断范围溢出
        n=max(x,n);m=max(y,m);//求矩阵的最大长和宽
        a[x][y]+=w;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
          a[i][j]+=(a[i-1][j]+a[i][j-1]-a[i-1][j-1]);//计算二维前缀和
    for(int i=R;i<=n;i++)//最坏遍历时间复杂度是o(n^2)
        for(int j=R;j<=m;j++)
        res=max(res,a[i][j]-a[i-R][j]-a[i][j-R]+a[i-R][j-R]);//找出轰炸的最大价值
    cout <<res<< endl;
    return 0;
}

这里需要注意的一个地方是,因为所以我们找出轰炸的最大价值时上面的求法其实是求红色面积边长减去1的面积最大价值(这个包含右方和下方的边,处理特殊情况,像题目中给出的输入输出样例就比较特殊),如果想真正求出红色面积所包含的价值(包括边),需要a[i][j]-a[i-R-1][j]-a[i][j-R-1]+a[i-R-1][j-R-1]。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值