P2234. 营业额统计

考点

  • 链表
  • 模拟

题解

见思路

思路

每次要找子序列中最接近当前元素的值,肯定希望其有序

平衡树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bits/stdc++.h>
using namespace std;
#define INF_MAX 0x3f3f3f3f
#define INF_MIN 0xc0c0c0c0
multiset<int> s;

int main()
{
int n, in, ans = 0;
cin >> n >> ans;
//塞入极大值和极小值是为了避免繁琐边界值的讨论
//正常情况下,it可能会是st.begin(),也有可能是st.end()
//加上极小值,it最小也只会出现在st.begin() + 1
//加上极大值,it最大也只会出现在st.end() - 1
s.emplace(ans), s.emplace(INF_MAX), s.emplace(INF_MIN);
for (int i = 2; i <= n; ++i)
{
cin >> in;
multiset<int>::iterator it = s.lower_bound(in);
ans += min(abs(in - *it), abs(in - *prev(it)));
s.emplace(in);
}
cout << ans;
return 0;
}

链表

先建立结构体,记录第几天及该天的营业额,并按照营业额排序

新建数组money,效果和结构体一样,下标为第几天,值为该天营业额

根据排序后的结构体数组中的天数,建立双向链表

这样一来,每次先从天数大的开始,从数组money获取其营业额并与相邻节点比较;比较结束后,将其删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
const int LEN = 1e5 + 10;
int pre[LEN], nxt[LEN], money[LEN];
struct Node
{
int money_, day_;
} arr[LEN];

int main()
{
int n, ans = 0;
cin >> n;
for (int i = 1; i <= n; ++i)
{
cin >> arr[i].money_;
arr[i].day_ = i;
money[i] = arr[i].money_;
}
sort(arr + 1, arr + 1 + n, [](Node &a, Node &b) -> bool
{ return a.money_ < b.money_; });
for (int i = 1; i <= n; ++i)
{
pre[arr[i].day_] = arr[i - 1].day_;
nxt[arr[i].day_] = arr[i + 1].day_;
}
for (int day = n; day >= 1; --day)
{
int l = pre[day], r = nxt[day], now = money[day];
if (l && r)
ans += min(abs(now - money[l]), abs(now - money[r]));//有前驱与后继
else if (!l && r)
ans += abs(now - money[r]);//无前驱但有后继
else if (l && !r)
ans += abs(now - money[l]);//有前驱但无后继
else
ans += now;//只有自己
//删除当前天数
nxt[l] = r;
pre[r] = l;
}
cout << ans;
return 0;
}