题目地址:
https://www.acwing.com/problem/content/267/
Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况。设第 i i i天的营业额为 a i a_i ai,则第 i i i天( i ≥ 2 i≥2 i≥2)的最小波动值 f i f_i fi被定义为: f i = min 1 ≤ j < i ∣ a i − a j ∣ f_i=\min_{1≤j<i}|a_i−a_j| fi=1≤j<imin∣ai−aj∣当最小波动值越大时,就说明营业情况越不稳定。而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。第一天的最小波动值为第一天的营业额 a 1 a_1 a1。
输入格式:
第一行为正整数
n
n
n,表示该公司从成立一直到现在的天数。接下来的
n
n
n行每行有一个整数
a
i
a_i
ai(有可能有负数),表示第
i
i
i天公司的营业额。
输出格式:
输出一个正整数,表示最小波动值的和。
数据范围:
n
≤
32767
,
a
i
≤
1
0
6
n≤32767,a_i≤10^6
n≤32767,ai≤106
即要实现一个数据结构,可以实现插入,找离 x x x最近的数这两个功能。后者可以转化为求前驱和后继的操作。可以用平衡树来实现,一个比较容易实现的版本是Treap。本题不需要记录cnt和size,直接当成每个数只出现一次就行了。参考https://blog.csdn.net/qq_46105170/article/details/118997891。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 33010, INF = 1e8;
int n;
struct Node {
// son[0]和son[1]分别是左右孩子的下标
int son[2];
int key, val;
}tr[N];
int root, idx;
int get_node(int key) {
tr[++idx].key = key;
tr[idx].val = rand();
return idx;
}
// d = 0代表左旋,d = 1代表右旋
void rotate(int &p, int d) {
int q = tr[p].son[d ^ 1];
tr[p].son[d ^ 1] = tr[q].son[d];
tr[q].son[d] = p;
p = q;
}
void insert(int &p, int key) {
if (!p) p = get_node(key);
else if (key < tr[p].key) {
insert(tr[p].son[0], key);
if (tr[tr[p].son[0]].val > tr[p].val) rotate(p, 1);
} else if (key > tr[p].key) {
insert(tr[p].son[1], key);
if (tr[tr[p].son[1]].val > tr[p].val) rotate(p, 0);
}
}
int get_prev(int p, int key) {
if (!p) return -INF;
if (tr[p].key > key) return get_prev(tr[p].son[0], key);
return max(tr[p].key, get_prev(tr[p].son[1], key));
}
int get_next(int p, int key) {
if (!p) return INF;
if (tr[p].key < key) return get_next(tr[p].son[1], key);
return min(tr[p].key, get_next(tr[p].son[0], key));
}
int main() {
scanf("%d", &n);
long res = 0;
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
if (i == 1) res += x;
else res += min(x - get_prev(root, x), get_next(root, x) - x);
insert(root, x);
}
printf("%ld\n", res);
return 0;
}
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。