前缀和及其应用

前缀和,简单来说,你输入了一串数,用s[i]表示a[1]~a[i]的所有元素的和,那么s数组记录的就是a的前缀和。

用前缀和来进行维护可以很好地节约时间复杂度,比如说有一串数,每次给定一个操作,询问一段区间内所有元素和,要求线性做法O(m+n),这时就不能使用两重循环枚举。我们可以使用前缀和,当询问区间l~r时,我们只要输出s[l]-s[r]就可以了。

前缀和同样可以用在矩阵上,如果用f[i][j]来表示从(1,1)到(i,j)之间所有元素的和,这样的话初始化代码就是:

f[i][j] += f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1];

这样我们在询问一个矩阵中的元素和时,他的计算公式就是

f[i][j] - f[x - 1][j] - f[i][y - 1] + f[x - 1][y - 1];

下面我们来看其他的应用。

例题1:

给定n个数ai,有m次操作,每个操作是给al~ar增加一个数k。最终输出操作完后的这n个数的值。要求一个O(n+m)的做法。

这种题怎么做呢?如果按最暴力的想法,我们会在每个询问区间内,进行一次循环,但是这样的作法不是线性的,不符合要求。

我们要选择具有代表性的元素来下手,也就是那些发生改变较少的元素。——张浩威

哪些元素的改变比较少呢?我们在一次区间操作之后,区间内的元素都发生了改变,显然不好,我们仔细观察后发现,区间端点与其旁边元素的差值变化比较小。如果在一段区间内+=i,那么就让左端点和其前面的元素的差值+2,右端点和其后面元素的差值-2。这样我们就可以做到线性操作了,只要开一个数组f来记录当前元素和前一个元素的差值即可。

此时我们会发现,a数组其实就是f数组的前缀和!也就是说这道题也可以转换成前缀和来做了。

矩阵的话也大致相同。

对于每次以(x,y)为左上角,(x2,y2)为右下角的矩阵操作,相当于是令s[x][y]+=k,s[x][y2+1]-=k,s[x2+1][y]-=k,s[x2+1][y2+1]+=k。

 

 

 

 

posted @ 2018-02-06 20:59  CaptainLi  阅读(310)  评论(0编辑  收藏  举报