本题的油箱无限大,所以当一个点的油价很便宜时,我们要在这个点买足够多的油,这个足够多的限制在哪里?就是能够支撑我们到下一个更便宜的点。至此思路就很明显了,在起点处是必须要买油的,当遇到一个比起点更低价格的点时,计算这两个点之间的距离(前缀和),用起点的价格买足够多的油,来到这个点之后继续向后寻找更便宜的油。
要注意的点是买的油一定是整数,例如点 1 1 1与点 2 2 2的距离是 10 10 10,每升油能让我们走 4 4 4,在起点处就必须买 3 3 3升油( 3 ∗ 4 = 12 > 10 3*4=12>10 3∗4=12>10)如果点 1 1 1与点 2 2 2的距离是 12 12 12,我们还是需要买 3 3 3升油,所以要买的油的数量 x x x与距离 d i s t a n c e distance distance的关系是 x = ⌈ d i s t a n c e d ⌉ x=\lceil\frac{distance}{d}\rceil x=⌈ddistance⌉,具体写代码时,为了避免浮点数或者取整操作,我们可以使 x = d i s t a n c e + d − 1 d x=\frac{distance+d-1}{d} x=ddistance+d−1,这个式子和上式是等价的,例如 10 + 4 − 1 4 = 3 \frac{10+4-1}{4}=3 410+4−1=3, 12 + 4 − 1 4 = 3 \frac{12+4-1}{4}=3 412+4−1=3。另外,到达点 2 2 2之后我们还剩 2 2 2升油,这 2 2 2升油是可以继续用的。
最终车一定要开到 n n n号点,所以如果在最后一个点时没有更新更便宜的油价,那么终点到上一个便宜点之间的距离是会被忽略的。所以最后要加一下开到终点的花费。
#include <bits/stdc++.h>
#define A 100010
using namespace std;
typedef long long ll;
int n, v[A], a[A];
ll ans, d, sum[A];
int main(int argc, char const *argv[]) {
cin >> n >> d;
for (int i = 2; i <= n; i++) {
scanf("%d", &v[i]);
sum[i] = sum[i - 1] + v[i];
}
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
int pos = 1;
ll oil = 0, leftoil = 0, minn = a[1];
for (int i = 2; i <= n; i++) {
if (a[i] < minn) {
oil = (sum[i] - sum[pos] - leftoil + d - 1) / d;
leftoil += oil * d - (sum[i] - sum[pos]);
ans += oil * minn;
minn = a[i];
pos = i;
}
}
ans += (sum[n] - sum[pos] - leftoil + d - 1) / d * minn;
cout << ans << endl;
}
由于做法中出现了乘法,所以代码写出之后需要关注一下是否会爆 i n t int int,每个变量的数据范围都是 1 e 5 1e5 1e5,前缀和 s u m [ n ] = n ∗ v [ i ] = 1 e 10 sum[n]=n*v[i]=1e10 sum[n]=n∗v[i]=1e10会爆 i n t int int, o i l ∗ d oil*d oil∗d和 o i l ∗ m i n n oil*minn oil∗minn也有可能爆 i n t int int,需要给相应的变量开上 l o n g l o n g long\ long long long。