>Description
阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。
阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。
>Input
第一行有一个正整数N,表示螺丝街住户的数量。
接下来的一行有N个正整数,其中第i个整数Si,表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8
接下来的一行有N个正整数,其中第i个整数Ai,表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<1000
>Output
输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。
>Sample Input
5
1 2 2 4 5
5 4 3 4 1
>Sample Output
12
17
21
24
27
>解题思路
看到题目想了一下准备用贪心,但是发现自己的贪心算法有很多bug打不下去,所以看了一下题解(豁然开朗)。
首先考虑疲劳值A,路程先不管,所以得出的ans在X的情况下为
a
n
s
=
s
u
m
(
a
[
1
X
]
)
+
2
∗
前
X
中
路
程
最
大
值
ans=sum(a[1 ~ X])+2*前X中路程最大值
ans=sum(a[1 X])+2∗前X中路程最大值
但是也有可能后面没选的a值较小的加上路程会大于选了的数,所以我们需要舍弃a值第X大的数(不能舍弃两个,是因为后面最大的路程加上两个较小的a,还不如后面最大的路程只加上一个小a,留下一个大a),这时的ans为
a
n
s
=
s
u
m
(
a
[
1
X
−
1
]
)
+
a
[
在
后
面
选
中
的
数
]
+
2
∗
选
中
的
路
程
ans = sum(a[1 ~ X-1])+a[在后面选中的数]+2*选中的路程
ans=sum(a[1 X−1])+a[在后面选中的数]+2∗选中的路程
这样做一下预处理就会简单很多了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct ooo
{
int s, c;
} a[100005];
int n, f[100005], x[100005], y[100005];
bool bmp (ooo aa, ooo bb) {return aa.c > bb.c;}
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++) scanf ("%d", &a[i].s);
for (int i = 1; i <= n; i++) scanf ("%d", &a[i].c);
sort (a + 1, a + 1 + n, bmp); //按照a排序
for (int i = 1; i <= n; i++) f[i] = f[i - 1] + a[i].c; //a前缀和
for (int i = 1; i <= n; i++) x[i] = max (x[i - 1], a[i].s); //前i中路程最大的
for (int i = n; i >= 1; i--) y[i] = max (y[i + 1], a[i].s * 2 + a[i].c);
//后i中路程及a最大的
for (int i = 1; i <= n; i++)
printf ("%d\n", max (f[i] + 2 * x[i], f[i - 1] + y[i + 1])); //输出最大值
//这里我有想过后者路程最大值仍然在前X中,但是这样的话一定是前者更大(自己想想)
return 0;
}