考点:思维
题意:给一个长度为 n n n 的数组 X X X 以及 a a a 和 b b b,并且 0 < X 1 < X 2 < ⋅ ⋅ ⋅ < X n 0<X_1 < X_2 < ··· < X_n 0<X1<X2<⋅⋅⋅<Xn ,求从 0 0 0 出发,到占领 X n X_n Xn 的最小花费。存在如下两个操作:
- 将起点从 C 1 C_1 C1 转移到 C 2 C_2 C2 ,花费 a ∗ ∣ C 1 − C 2 ∣ a * |C_1 - C_2| a∗∣C1−C2∣
- 从起点 C 1 C_1 C1 出发占领 C 2 C_2 C2,花费 b ∗ ∣ C 1 − C 2 ∣ b*|C_1 - C_2| b∗∣C1−C2∣
需要注意的是,当要被占领的 C 2 C_2 C2 与起点 C 1 C_1 C1 之间存在未被占领的点时, C 2 C_2 C2 将不能被占领。转而言之,需要依次占领 X 1 、 X 2 、 . . . 、 X n X_1、X_2、...、X_n X1、X2、...、Xn 。
❌思路:通过题意能发现占领点的值一定会比出发点的值大,若要转移起点,则转移终点点一定会比起点大,即 C 2 > C 1 C_2 > C_1 C2>C1。面对一个新的待攻占点 C 3 C_3 C3,我们有两种选择,①直接从起点 C 1 C_1 C1 出发攻占待攻占点 C 3 C_3 C3,花费为 b ∗ ∣ C 1 − C 2 ∣ b * |C_1 - C_2| b∗∣C1−C2∣,②先转移起点 C 1 C_1 C1 转移到 C 2 C_2 C2,再从新的起点 C 2 C_2 C2 出发到新的待攻占点 C 3 C_3 C3。两种情况取最小值。提取公式: a ∗ ( C 2 − C 1 ) + b ∗ ( C 3 − C 2 ) a * (C_2 - C_1) + b * (C_3 - C_2) a∗(C2−C1)+b∗(C3−C2) ,用二分找出合适的点 C 2 C_2 C2 ,此思路完全错误,过不了样例,可用此思路推一下第二个例子,便可知道错误之处。
✔思路:需要考虑的是从哪个点出发去攻占一个带攻占的点,转移起点会花费 a ∗ ∣ C 2 − C 1 ∣ a * |C_2 - C_1| a∗∣C2−C1∣ ,需要判断这花费值不值,若后面还有 m m m 个带攻占点,此时存在关系 a ∗ ∣ C 2 − C 1 ∣ ≤ ∣ C 2 − C 1 ∣ ∗ m ∗ b a * |C_2 - C_1| \leq |C_2 - C_1| * m * b a∗∣C2−C1∣≤∣C2−C1∣∗m∗b ,则表明将起点转移到 C 2 C_2 C2 是值得的,这样就能 A C AC AC 了。
#include<stdio.h>
typedef long long ll;
const int N = 2e5 + 10;
ll s[N];
int n,a,b,k;
int main() {
int t;
scanf("%d",&t);
while(t --) {
scanf("%d %d %d",&n,&a,&b);
for(int i=1;i<=n;i++) scanf("%lld",&s[i]);
ll res = 0;
int l = 0;
for(int i=1;i<=n;i++) {
res += b * (s[i] - s[l]);
if((s[i] - s[l]) * a <= (s[i] - s[l]) * b * 1ll * (n - i)) {
res += a * (s[i] - s[l]);
l = i;
}
}
printf("%lld\n",res);
}
return 0;
}