前缀和、差分总结归纳

差分定义:

差分(Difference)是一种常用的技巧,用于处理区间的增量更新和查询。差分数组是原始数组的相邻元素之间的差值构成的数组。通过差分数组,我们可以实现对区间的增量更新,而不需要每次都重新计算整个区间的值。 

 

差分数组的使用方法如下:

1. 初始化差分数组:将原始数组的第一个元素放入差分数组中,其他元素为原始数组相邻两元素之差。 

2. 区间增量更新:对于区间  [l, r] ,将差分数组 diff 的 l 位置加上增量 inc , r+1 位置减去增量 inc 。 

3. 恢复原始数组:通过差分数组计算出原始数组。 

 

差分常用于解决一些区间更新问题,如区间增量更新、区间赋值等。

 

前缀和定义:

前缀和(Prefix Sum)是另一种常用的技巧,用于快速计算数组中某个位置前所有元素的和。前缀和数组是原始数组的前缀和构成的数组,可以帮助我们快速计算区间的和。 

 

一般来说,需要使用前缀和的题目具有以下特征:

1. 需要频繁查询某个区间的和,如区间求和、区间最值等问题。 

2. 需要快速计算某个位置前所有元素的累积和。 

3. 题目中涉及到多次区间和的计算,可以考虑使用前缀和来优化计算过程。 

 

综上:通过差分和前缀和这两种技巧,我们可以在一些问题中更高效地处理区间操作和区间和的计算。在解决涉及区间操作和区间和的问题时,这两种技巧都是非常有用的工具。

eg1:数组的价值:​​​​​​​

给你一个长度为 n 的数组,编号为1~n ,现在我们从这个位置中选择一个位置k,则这个数组的价值定义为:

一共有种n选择方案,现在想让你找到所有方案中这个价值最大是多少?

【输入格式】

输入第一行一个整数 ,代表数组的长度

接下来 n行,每一行一个整数 ai,代表数组元素的每一个数

【输出格式】

对于每一组测试数据,输出一个答案代表要求的最大价值

【样例输入】

5

2

1

4

3

5

【样例输出】

168

【说明】

数据规模:

1≤n≤1000000  ,  1≤ai≤100

​​​​​​​

算法思路:

1.利用前缀和提前求出 s[i]=a[1]+a[2]+...+a[i],

2.再用一次循环求前 i 项的平方和 sum+=a[i] * a[i]

3.接着就可以由 price = sum * (s[n]-s[i]) 求出数组价值即可。

4.对每次求得的 price 求最大值,最终答案就是数组的最大价值。

完整代码:

#include <bits/stdc++.h>
using namespace std;
int a[1000005];
int s[1000005];// 前缀和数组
int main(){
    int n;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        s[i] = s[i-1] + a[i]; // 求前缀和
    }
    // 求平方和,根据数据规模如果为 int 类型可能栈溢出,所以定义为long long 类型
    long long sum = 0;
    long long price = INT_MIN;// int 类型最小数
    for(int i=1;i<=n;i++){
        sum = sum + a[i] * a[i];
        // 根据数组价值的定义进行模拟:
        // 即前 i 个元素的平方和乘上后 n-i 个元素之和
        long long temp = sum * (s[n]-s[i]);
        // 比较price,求其最大价值
        price = max(price, temp);
    }
    cout << price << "\n";

    return 0;
}

eg2:Color the ball (hdu1556)

原题链接:Problem - 1556

问题描述

N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?

输入:每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,

每行包括2个整数a b(1 <= a <= b <= N)。

输出:每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。

差分定义概念介绍:

在这里给现介绍一下差分数组d[k]的定义d[k] = a[k]-a[k-1],即相邻两个元素的差。

那反之则有:a[k] = d[k] + a[k-1],而a[k-1] = d[k-1] + a[k-2]...以此类推,

a[k]=d[1]+d[2]+d[3]+...d[k]

因此就得到了一维查分的递推公式:a[i]=a[i-1]+d[i]

算法分析:

该题每次都是对区间[a,b]进行涂一次色,即每次都是对某个区间的数进行更新操作,

则知此题考点是差分

则根据上述的差分步骤:

完整代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N],d[N];
int main(){
    int n;
    while(~scanf("%d", &n)){
        memset(d, 0, sizeof(d));
        memset(a, 0, sizeof(a));
        for(int i=1; i<=n; i++){
            int l, r;
            cin >> l >> r; // 涂颜色的区间左右边界
        //  对区间进行修改
            d[l]++;
            d[r+1]--;
        }
        for(int i=1; i<=n; i++){
            // 差分递推公式
            a[i] += a[i-1] + d[i];
            // 打印修改过的数组
            if(i == n) cout << a[i];
            else cout << a[i] << " ";
        }
        cout << endl;
    }
    
    
    return 0;
}

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值