题目大意
在一条坐标轴上有
n
n
n个点需要占领,每个节点在
x
i
x_i
xi,初始节点在
0
0
0处,且基地也在
0
0
0处
每次行动时,设当前基地在
p
p
p处,那么可以做以下行动:
- 把基地移动到一个已经占领的点 x i x_i xi,耗费 a ∗ ∣ x i − p ∣ a * |x_i - p| a∗∣xi−p∣
- 占领一个没有被占领的节点,消耗 b ∗ ∣ x i − p ∣ b * |x_i - p| b∗∣xi−p∣
给定
a
,
b
,
x
i
(
1
≤
n
≤
2
∗
1
0
5
,
1
≤
a
,
b
≤
1
0
5
)
a,b,x_i(1\le n \le 2*10^5, 1 \le a, b \le 10^5)
a,b,xi(1≤n≤2∗105,1≤a,b≤105),求占领所有节点的耗费最小值。
题目链接
思路
我们来考虑占领的最终状况。
我们把基地定在了
x
p
x_p
xp处,然后把所有点给占领了。
我们设
s
u
m
1
sum1
sum1是点的距离的前缀和。
那么占领
x
p
x_p
xp之后的所有点的费用就是
(
s
u
m
1
[
n
]
−
s
u
m
1
[
i
]
−
(
n
−
i
)
∗
x
[
i
]
)
∗
b
(sum1[n] - sum1[i] - (n - i) * x[i]) * b
(sum1[n]−sum1[i]−(n−i)∗x[i])∗b
那么前面的点呢?
我们发现,不管我们什么时候移动基地,移动基地的费用都是
a
∗
x
p
a * x_p
a∗xp
所以我们最有解法一定是占领一个点,那么就把基地移动过去。这样我们占领的费用就是
b
∗
x
p
b * x_p
b∗xp
可以发现,指定最终基地的落脚点,可以 O ( 1 ) O(1) O(1)的算出费用,那么我们就不妨枚举基地的落脚点,然后更新答案。
代码
#include <cstdio>
#include <iostream>
using namespace std;
const int maxN = 2e5 + 7;
int T, n;
long long a, b, x[maxN], sum1[maxN];
int main()
{
scanf("%d", &T);
while(T--) {
scanf("%d%lld%lld", &n, &a, &b);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &x[i]);
sum1[i] = sum1[i - 1] + x[i];
}
long long ans = 1LL << 62;
for(int i = 0; i <= n; ++i) {
long long forward = x[i] * b, after = (sum1[n] - sum1[i] - (n - i) * x[i]) * b;
ans = min(ans, forward + after + a * x[i]);
}
printf("%lld\n", ans);
}
return 0;
}