题目描述
小苞准备开着车沿着公路自驾。
公路上一共有 n 个站点,编号为从 1 到 n。其中站点 i 与站点 i+1 的距离为 vi 公里。
公路上每个站点都可以加油,编号为 i 的站点一升油的价格为 ai 元,且每个站点只出售整数升的油。
小苞想从站点 1 开车到站点 n,一开始小苞在站点 1 且车的油箱是空的。已知车的油箱足够大,可以装下任意多的油,且每升油可以让车前进 d 公里。问小苞从站点 1 开到站点 n,至少要花多少钱加油?
输入格式
输入的第一行包含两个正整数 n 和 d,分别表示公路上站点的数量和车每升油可以前进的距离。
输入的第二行包含 n−1 个正整数 v1,v2…vn−1,分别表示站点间的距离。
输入的第三行包含 n 个正整数 a1,a2…an,分别表示在不同站点加油的价格。
输出格式
输出一行,仅包含一个正整数,表示从站点 1 开到站点 n,小苞至少要花多少钱加油。
输入输出样例
输入 #1复制
5 4 10 10 10 10 9 8 9 6 5
输出 #1复制
79
说明/提示
【样例 1 解释】
最优方案下:小苞在站点 1 买了 3 升油,在站点 2 购买了 5 升油,在站点 4 购买了 2 升油。
【样例 2】
见选手目录下的 road/road2.in 与 road/road2.ans。
【数据范围】
对于所有测试数据保证:1≤n≤10^5,1≤d≤10^5,1≤vi≤10^5,1≤ai≤10^5。
测试点 | n≤n≤ | 特殊性质 |
---|---|---|
1∼5 | 8 | 无 |
6∼10 | 10^3 | 无 |
11∼13 | 10^5 | A |
14∼16 | 10^5 | B |
17∼20 | 10^5 | 无 |
- 特殊性质 A:站点 1 的油价最低。
- 特殊性质 B:对于所有 1≤i<n,vi 为 d 的倍数。
解题思路:
这道题可以考虑贪心,让车跑尽可能多的路程之后再去加油,由于车的油箱是无限大的,所以可以先考虑能跑到哪一个站点,然后在这些可以跑到的站点中选择一个价钱最低的加油,然后向下一个站点开,一直重复直到最后到达最后一个站点。
这个不能叫做贪心了,是贪心+反悔(回去加油)
先放上代码:
AC code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ld long double
#define FOR(x,a,b,c) for(int x=a;x<=b;x+=c)
#define MFOR(x,a,b,c) for(int x=a;x>=b;x-=c)
#define MPFOR(x,a,b,c) for(int x=a;a<=b;x*=c)
const int N3=1e3+10;
const int N=1e6+10;
const long double esp=1e-8;
int gcd(int a,int b){
int c=a%b;
while(a%b!=0){
a=b;
b=c;
c=a%b;
}
return b;
}
int lcm(int x,int y){
return (x*y)/gcd(x,y);
}
ll a[N],b[N],c[N];//a:存放距离 b:存放距离起点的距离 c:存放价钱
priority_queue<ll> q;//可以用一个ll minx=100010代替
//做的时候脑子抽风写了个优先队列提升时间复杂度,真的没必要,直接算到当前最小的加油站价格的值就行,小顶堆的话如果一个加油站不是无限油量才有用
ll ans=0;//最后的付的钱
ll n,d;
ll sum=0;//当前这个站点离着起始点有多远(不必须写,不写也就麻烦一点)
ll nowi=0;//记录当前可以开到距离起点多远的地方
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
scanf("%lld %lld",&n,&d);
a[1]=0;
FOR(i,2,n,1){
scanf("%lld",&a[i]);
sum+=a[i];
b[i]=sum;
}
FOR(i,1,n,1){
scanf("%lld",&c[i]);
}
// FOR(i,1,n,1){
// cout<<b[i]<<" ";
// }
for(int i=1;i<=n;i++){
if(nowi>=b[i]){
q.push(-c[i]);//入堆,可以用minx=min(minx,c[i])代替
}
else{
ll t=b[i]-nowi;
ll tt=ceil(1.0*t/d);
nowi+=tt*d;
ans+=tt*(-q.top());//加上这次加油需要的钱,可以用ans+=tt*minx代替
q.push(-c[i]);//现在可以走到这里,放入可以加油的站点中,可以用minx=min(minx,c[i])代替
}
}
printf("%lld\n",ans);
//fclose(stdin);
//fclose(stdout);
return 0;
}
需要注意的几个点:
1.开long long,因为一个距离和油量到了10^5,距离最后会到10^10,int类型直接炸,int会WA一半,50分。
2.我这个小顶堆真的没用,实际上这样反倒会增加时间复杂度变为O(nlogn),还好不是卡着10^7的数据范围,不然用小顶堆会时间会炸。
那要是不会写贪心咋办?
15分很好拿
特殊性质 A:站点 1 的油价最低。
所以可以直接从站点1加上可以到终点的油量,然后中途不再加油,15分拿到。
剩下特殊性质B没怎么想,因为我会贪心。
有任何错误请评论指正作者将给予修改。