差分定义:
差分(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;
}