在做洛谷P2367语文成绩这道题的时候,发现用的就是一些差分的基础知识,于是乎就心血来潮写下了这篇文章
一、什么是差分
差分,先从这个词的构成角度来看,应该是与两数之差以及分块思想有关。
让我们先给定一个简单数列:
arr[1] = 1;
arr[2] = 2;
arr[3] = 4;
那我们的差分是怎么定义的呢,且看:
//d数组记录的就是差分
d[1] = arr[1] = 1;
d[2] = arr[2] - arr[1] = 1;
d[3] = arr[3] - arr[2] = 2;
d[4] = 0 - arr[3] = -4;
显而易见,差分数组 d 记录的就是数列中一个数和它前面的那个数之差。
二、差分的一些基本性质
现在我们已经知道了差分的定义,那差分能用来干什么呢?
其实差分大部分情况都是用来解决一些对区间操作的问题的。
所以接下来,我们先来看第一个基本性质:
性质1:将原序列区间[L,R]中的元素全部 + k,可以转化操作为差分序列L处 + k,R+1处 - k。
如对上述序列区间[2,3]每个数加1,即:
arr[2] = 3; arr[3] = 5;
再看差分数组d
d[2] = arr[2] - arr[1] = 2; d[4] = 0 - arr[3] = -5;
对比原来的差分数组d,想必此条重要的性质就很清楚了吧。
再看看另外一个简单的性质:
性质2:差分序列求前缀和可得原序列
先说一下前缀和是什么。
前缀和,顾名思义,即一段序列的前 i 项之和。 其实就类似于数列的前n项和。
定义数组 s 保存上述差分数列的前缀和。
s[1] = d[1] = 1;
s[2] = d[2] + d[1] = 2;
s[3] = d[3] + d[2] + d[1] = 4;
知道了前缀和的定义,再把差分数组的定义代入每个前缀和的式子中,我想这个性质就不难理解了。
有了基础知识,接下来我们就把这道题干掉吧。
题目:P2367语文成绩
代码:
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstring>
#include <string>
#include <sstream>
#include <stack>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <fstream>
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define LNF = 0x3f3f3f3f3f3f3f3f;
using namespace std;
const int maxn = 5000002;
int n, p, minn = INF, arr[maxn], d[maxn], s[maxn];
inline int read() {
int x = 0, f = 1; char c = getchar();
while (!isdigit(c)) { if (c == '-') f *= -1; c = getchar(); }
while (isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
inline void put(int x) {
if (x < 0) x = -x;
if (x > 9) put(x / 10);
putchar(x % 10 + '0');
}
int main() {
n = read(), p = read();
d[1] = arr[1] = read();
for (int i = 2; i <= n; i++) {
arr[i] = read();
d[i] = arr[i] - arr[i - 1];
}
for (int i = 1; i <= p; i++) {
int x = read(), y = read(), z = read();
d[x] += z;
d[y + 1] -= z;
}
for (int i = 1; i <= n; i++) {
arr[i] = arr[i - 1] + d[i];
if (arr[i] < minn) minn = arr[i];
}
put(minn);
return 0;
}