[CSP-J 2023] 公路 题解

题面&测评链接:

解法:

思路

分析题目。思考,如何用最少代价达到目的。

先明确一点:第 1 个加油站一定要加油,第 n 个加油站一定不加油。

再来想想,设 a_i 为第 i 个加油站的价格,如果在第 x 个加油站加的话,在哪里加下一次油呢?如果存在一个 y ,使得在满足 y > x , a_y<a_x 的情况下 y 达到最小值,那就说明 y 加油站比 x 加油站便宜,既然如此,那y以后的油就在 y 加油站买就好了。

于是我们就有了如下贪心思路:

  1. 对于 x 加油站,我们确定要在这个加油站加油。(最开始 x=1
  2. 找到一个 y 加油站,使得在满足 y > x , a_y<a_x 的情况下 y 达到最小值。
  3. 我们花钱买油跑到 y 加油站。
  4. x\leftarrow y,把 y 的值赋值给 x。
  5. 如果 x<n,转至第一步。
  6. 输出答案,结束。
备注
  • 数据范围要注意。我们看题可知:

对于所有测试数据保证:$1 \leq n \leq 10^5$$1 \leq d \leq 10^5$$1 \leq v_i \leq 10^5$$1 \leq a_i \leq 10^5$

考虑答案最大是多少,思考最不利情况:即油的单价最贵,路程最远,每升油跑的距离最少——n=10^5d=1$\forall i,v_i=10^5$$\forall i,a_{i}=10^5$,此时答案为:99999\times10^5\times10^5=9.9999\times10^{10},很明显:int 类型装不下了,要开 long long

  • 既然第 n 个加油站一定不加油,我们不妨设第 n 个加油站的油的单价为 0,即a_n=0。这样根据贪心思路,最后一次买油必定是买到第 n 个加油站。

AC 代码:

#include<bits/stdc++.h>
#define ll long long
#define lf double
using namespace std;
const int N=100002;
ll n,d,w[N],price[N],loc=1,min_price[N],total_w,km,ans;
inline ll max_(ll AA,ll BB)
{//因为<algorithm>头文件中的max函数的参数只能是int类型,所以只能自己手打一个了。
	return (AA>BB?AA:BB);
}
int main()
{
	
	scanf("%lld%lld",&n,&d);
	for(ll i=2;i<=n;i++)
		scanf("%lld",&w[i]);//w[i]:从 i-1 站点到 i 站点的距离
	for(ll j=1;j<=n-1;j++)//最后一个加油站的单价不读了,正好就可以空着为0
		scanf("%lld",&price[j]);
	
	ll i=1;
	while(loc<n)//loc即前面说的x站点
	{
		i++;//找一个合适的y站点,i就是y
		total_w+=w[i];//total_w:这次买油要跑的公里数。
		if(price[i]<price[loc])//若符合条件
		{
            //购买
			total_w-=km;//km即每次买完油跑到目标站点不加油后还能跑的公里数
			if(total_w<=0)
			{
				km=(-1)*total_w;
				total_w=0;
			}
			else
			{
				ll L=ceil((double)total_w/d);//L是这次买油要买几升。
				km=L*d-total_w;
				total_w=0;
				ans+=L*price[loc];
			}
			loc=i;
		}
	}
	printf("%lld",ans);
	return 0;
}

对于程序实现后复杂度的问题,因为存储以及计算都是线性的,所以时间复杂度:O(n),空间复杂度也是:O(n)n\leq 10^5,所以可以过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值