4.3 KiB
AcWing
464
. 推销员
一、理解测试用例
s[i]: 1 2 3 4 5
a[i]: 1 2 3 4 5
① 取1
个:5*2+5=15
② 取2
个:(5+4)+2*5=19
③ 取3
个:(5+4+5)+2*5=22
④ 取4
个:(2+3+4+5)+2*5=24
⑤ 取5
个:(1+2+3+4+5)+2*5=25
二、解题思路
距离是真的烦人,那就先不管它吧。因为想要疲劳值最大,那么先 按照疲劳值从大到小排序 一遍。
此时,可以判断出,最大值 可能 为:对于每个X
,只要加上前X
大的疲劳值,再加上 这些数中距离最远 的并 乘以2
,也就是:\sum_{i=1}^{X}(a[i])+s[j]∗2$$
其中,s[j]
表示前 X
个距离最远的。
但是,推销员可以通过 走远一点,虽然疲劳值比前面小,但是有可能把路程一算,反而更大。
因此,可以把a[]
,即疲劳值中,前X
大中的最小值,即第X
大的那一家舍去,看看能不能通过走更远来换取更大的疲劳值总和。
而从后面看,一定也会存在一个最大值,把这个最大值和前面X−1
个疲劳值总和加起来,看看会不会比前面第一种的情况大。
证明:只需舍去最小值来走更远,无需舍去更多数来走更远。
其实这也不是一个证明..
因为已经从大到小排序了,所以,如果舍去2
个疲劳值,那么后面只会在加上两个更小的疲劳值,以及两个之间最大的距离并乘2
,那么这样还不如只舍去一个。
2
个不行,那么2
个以上更是不行了。
举栗子
硬讲太累了,还是用一个例子吧。
s[i]:1,3,4,5,11
a[i]:5,4,2,1,1
- 若
X==1
:- 直接取,值为:
1×2+5=7
- 如果舍去当前(最小)的往后跑,值为:
11×2+1=23
- 直接取,值为:
所以,最大值就为max(7,23)=23
。
- 若
X==2
:-
直接取,值为:
3×2+5+4=15
-
把其中 最小 值舍去,也就是
4
去掉,往后跑值为:11×2+1+5=28
,那么最大值为max(15,28)=28
。 -
若把次小疲劳值,即
5
,也往后跑,那么值为11×2+1=23
,可以发现,距离并未因此改变,仍为11
,而位置移后,疲劳值只会减少,故只能移动最小疲劳值。
-
那么,最后一个问题,酱紫复杂度是会炸掉的,原因分析:
我们需要哪些信息呢?
① sum[i]:a[i]
数组前i
位的前缀和,比如上面的5+4
② 除了计算疲劳值的前缀和,还需要一个前i
个住房中,找到最大的距离值,这是题目中要求的数据,它能不能预处理出来呢?答案是可以的:从i \sim n
一路max
pk
不就记录下来了吗~
我们用g[i]
来记录这个信息。
③ 把前i
位中第i
位去掉,保留前i-1
位,那么,需要知道后面这一堆住房中距离的最大值。
很明显,这里在倒序由后向前进行PK
记录即可。这里有一个坑点,就是如果你决策了选择某个住房,那么这个距离的最大值你肯定是妥妥的享用了,但不要忘记还要加这住房的疲劳值a[i].b
这样子预处理,就可以实现O(nlogn)
啦 qaq
!
最终二选一就可以了~
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n; // n个客户
int sum[N], g[N], h[N]; // 疲劳值前缀和 前i个最大值 后i个最大值
struct Node {
int s; // 距离
int b; // 疲劳
const bool operator<(const Node &W) {
return b > W.b;
}
} a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i].s; // 住户i到入口的距离
for (int i = 1; i <= n; i++) cin >> a[i].b; // 向i住户推销产品会积累的疲劳值
sort(a + 1, a + 1 + n); // 按疲劳由大到小排序
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i].b; // 预算出疲劳值的前缀和
for (int i = 1; i <= n; i++) g[i] = max(g[i - 1], 2 * a[i].s); // 前i个距离最大值
for (int i = n; i >= 1; i--) h[i] = max(h[i + 1], 2 * a[i].s + a[i].b); // 后i个距离最大值
for (int i = 1; i <= n; i++) printf("%d\n", max(sum[i] + g[i], sum[i - 1] + h[i]));
return 0;
}