题解 P9749 [CSP-J 2023] 公路
思维好题。
思路
以下为考场思路。
读题,有几个关键元素。
- 两点间的路程。
- 每个点的油价。
- 每升油能前进的路程。
- 油箱足够大。
油箱足够大的意思就是,油箱无限。
莫名想起了P5662 [CSP-J2019] 纪念品。
在纪念品一题中,因为可以无限交易,所以可以看做每一天都把所有的卖掉,然后再按需求买进。
而在本题中,因为油箱无限,所以可以看作当我在第
每当我们找到了一个新的最便宜的站点,那么肯定不会在其前面的站点买油,就这新站点最便宜。
那什么时候我们会更换买油的地方呢?当前站点成为新的最便宜的站点时,之后我们会选择在当前站点买油。
因此,我们只需要不断找到更便宜的站点,并在找到的最便宜的站点买油即可。每找到一个更便宜的站点,结算一次,要从上一个最便宜站点买够油开到当前最便宜的站点。
我们可以通过前缀和来快速求出任意两站点间的路程。
注意
- 要存还没花完的路程(把油转化成路程存下来)。
- 要开
long long。 - 在终点记得再结算一次。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node{
int x,id;
};
int n,d;
ll v[100003];
int a;
ll w;
ll tt;
ll ans;
node lst;//记录最便宜的站点
int main(){
scanf("%d%d",&n,&d);
for(int i=2;i<=n;i++){
scanf("%lld",&v[i]);
v[i]+=v[i-1];//求前缀和
}
for(int i=1;i<=n;i++){
scanf("%d",&a);
if(i==1){//肯定在第一个站点要买油。
lst.x=a;
lst.id=i;
}
else if(a<lst.x){
tt=(v[i]-v[lst.id]-w+d-1)/d;//从上一个最便宜的站点到当前最便宜的站点要多少油(向上取整)
w+=tt*d-(v[i]-v[lst.id]);//还余下多少路程没花完
ans+=tt*lst.x;//结算花费
lst.x=a;
lst.id=i;
}
}
ans+=(v[n]-v[lst.id]-w+d-1)/d*lst.x;//最后在终点还要结算一次
printf("%lld",ans);
return 0;
}