前缀和算法

描述:

前缀和是一种预处理,在之后的计算中直接应用前面已经算出的结果。

例题

题目链接
有数字1-n,然后m个l,r查询,构造一个序列,使得查询的区间和的和最大值;
输出和。

思路:差分前缀和求出每个数字被查询的次数,然后sort排序,一次赋值n到1,最大的对应n

#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;

//差分前缀和算法
ll vis[maxn], cnt[maxn];
int main(){
    int n, m;
    cin>>n>>m;
    int l ,r;

	//差分前缀和处理
    for(int i = 0; i < m; i++){
        scanf("%d%d", &l, &r);
        vis[r+1]-=1;
        vis[l]+=1;
    }
    for(int i = 1; i <= n; i++){
        vis[i]+= vis[i-1];
    }
    ll sum = 0;
    sort(vis+1, vis+n+1);
    for(int i = n; i > 0;i--){
        sum+=i*vis[i];
    }
    printf("%lld\n", sum);

    return 0;
}

一维前缀和:

s[i] = a[1]+a[2]+a[3]+…+a[n]

二维前缀和

s[i][j] = a[i’][j’]的和(1<=i’<=i, 1<=j’<=j)
有一点像“矩阵的面积”那样,把一整块区域的值都加起来。

前缀和用途

参考博客1
参考博客2
一般用来求前缀和
一维:给出n个数的序列,要求回答m次询问,每次询问下标l到r的和。

  1. 朴素做法:每次都执行加和操作,输出结果,显然会超时。
  2. 超时的原因:重复计算。
  3. 改进方法:提前算好了每个位置的前缀和,然后用s[r] - s[l],结果即为询问的答案。
    ——这样使得计算量大大减少,二维也是如此。
    前缀和算法_第1张图片
    前缀和算法_第2张图片

用差分实现前缀和:

给定一个长度为n的数列a,要求支持操作add(l ,r, val),表示对a[l]~a[r]的每个数加上val,并求修改之后的序列。

  1. 暴力显然超时;
  2. 考虑差分做法。辅助数组c,记录某个位置上的总改变量;
  3. c[i]表示i~n这些元素都加上c[i]这个数;
  4. 对[l, r]区间进行加值操作,在c[l]处加val,在c[r+1]处减val即可维护;
  5. 最后第i个位置改变了多少,只需要求一下c前缀和即可
对于二维:

参考博客
对于二维的情况,一个n*m的矩阵,要求支持操作add(x1,y1,x2,y2,a),
表示对于以(x1,y1)为左下角,
(x2,y2)为右上角的矩形区域,
每个元素都加上a。
要求修改后的矩阵。

做法和一维类似:

  1. 用数组c存储总改变量
  2. 在c[x1][y1]处加上a,
  3. 在c[x2+1][y1]和c[x1][y2+1]处减a,
  4. 在c[x2+1][y2+1]再加上a。
  5. 最后(i,j)位置上的数值就是c数组在(i,j)位置的前缀和。

你可能感兴趣的:(Code200+,前缀和算法)