题意
一条直线上有 N ( N ≤ 1 0 5 ) N(N\leq10^5) N(N≤105)个点,每个点有位置 p i p_i pi和权值 a i a_i ai。求从 0 0 0点开始,走过 k = 1 , 2 , … N k=1,2,\dots N k=1,2,…N个点并回到原点,且不走多余路程所能得到的最大权值是多少。也就是说,一次行走集合为 S S S的点的权值计算方式为 ( ∑ i ∈ S a i ) + max i ∈ S 2 p i (\sum_{i \in S}a_i) +\max_{i\in S} 2p_i (∑i∈Sai)+maxi∈S2pi。
解题思路
由于
N
N
N很大,所以DP什么的估计是行不通的,做题的时候想了很久也没想到有效的贪心算法。看来普及组的贪心题也是有点神仙的。
先从
k
=
1
k=1
k=1开始想,这个时候答案显然是
2
p
i
+
a
i
2p_i+a_i
2pi+ai最大的那个。当
k
=
2
k=2
k=2的时候,那么有两种情况。如果保留之前的那个点,那么增量要么是一个很大的
2
p
j
−
2
p
i
2p_j-2p_i
2pj−2pi,要么是一个
a
j
a_j
aj而不可能同时增加。
否则,假设有另外两个点
j
,
k
j,k
j,k,那么总权值为
a
j
+
2
p
j
+
a
k
+
2
p
j
−
m
i
n
(
2
p
j
,
2
p
k
)
a_j+2p_j+a_k+2p_j-min(2p_j,2p_k)
aj+2pj+ak+2pj−min(2pj,2pk)。如果让
p
k
>
p
j
p_k>p_j
pk>pj,那么原式子就是
a
j
+
a
k
+
2
p
k
a_j+a_k+2p_k
aj+ak+2pk。
那么考虑这两种情况下的最优解,情况一为
a
i
+
a
j
+
2
p
j
a_i+a_j+2p_j
ai+aj+2pj或者
a
i
+
a
j
+
2
p
i
a_i+a_j+2p_i
ai+aj+2pi,情况二为
a
j
+
a
k
+
2
p
k
a_j+a_k+2p_k
aj+ak+2pk。我们可以发现式子很相近,但是由于最大值只能是
a
i
+
2
p
i
a_i+2p_i
ai+2pi,所以情况二可以和情况1合并。并且
a
j
+
2
p
j
≤
a
i
+
2
p
i
a_j+2p_j\leq a_i + 2p_i
aj+2pj≤ai+2pi,所以
a
a
a的大小成了至关重要的因素。
我们可以把情况推广到
k
>
2
k>2
k>2的情形,对于某个
k
k
k,一定有权值为
∑
i
=
1
k
−
1
a
i
+
a
j
+
2
p
j
\sum_{i=1}^{k-1}a_i+a_j+2p_j
∑i=1k−1ai+aj+2pj,此时要么
a
j
+
2
p
j
a_j+2p_j
aj+2pj占据绝对优势,要么
∑
i
=
1
n
−
1
a
i
\sum_{i=1}^{n-1}a_i
∑i=1n−1ai占据绝对优势才能胜出。简单来说,就是要么选择
k
k
k个
a
a
a值最大的点,要么选择
k
−
1
k-1
k−1个
a
a
a值最大的点和一个不在
k
−
1
k-1
k−1个点中的
a
j
+
2
p
j
a_j + 2p_j
aj+2pj最大值,那么两种情况取最大值就是当前最优决策。
具体实现可以先把点按照
a
a
a值从大到小排好序并记录前缀和
p
r
e
f
pref
pref,然后维护一个从
N
N
N到
1
1
1的逆序最大
a
j
+
2
p
j
a_j+2p_j
aj+2pj叫做
s
u
f
suf
suf。此外,我们还需要预先计算出前
i
i
i个点的最远距离
c
u
r
P
curP
curP。这样我们的决策就是
max
{
p
r
e
f
[
i
−
1
]
+
s
u
f
[
i
]
,
p
r
e
f
[
i
]
+
c
u
r
P
[
i
]
}
\max\{pref[i-1]+suf[i], pref[i]+curP[i]\}
max{pref[i−1]+suf[i],pref[i]+curP[i]}。由于上面的推导可知,这样的贪心策略是正确的。
(累死了)
时间复杂度
O ( N log N ) O(N\log{N}) O(NlogN)
代码
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int MAXN = 100005;
const int INF2 = 0x3f3f3f3f;
int n, m, k;
struct Object{
int p, a;
bool operator<(const Object& b) const {
return a > b.a;
}
};
int pref[MAXN], maxp[MAXN], maxv[MAXN];
Object objects[MAXN];
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &objects[i].p);
}
for(int i = 1; i <= n; i++){
scanf("%d", &objects[i].a);
}
sort(objects + 1, objects + n + 1);
for(int i = 1; i <= n; i++){
pref[i] = pref[i - 1] + objects[i].a;
maxp[i] = max(maxp[i - 1], objects[i].p);
}
for(int i = n; i >= 1; i--){
maxv[i] = max(maxv[i + 1], objects[i].p * 2 + objects[i].a);
}
for(int i = 1; i <= n; i++){
printf("%d\n", max(pref[i - 1] + maxv[i], pref[i] + maxp[i] * 2));
}
return 0;
}