组队赛8:Journey to the "The World's Start" 二分+单调队列优化dp

参考来源

https://www.cnblogs.com/hua-dong/p/9460761.html

思路

二分假设地铁卡能走的最短的距离,找到这个最小值后,往大于等于这个距离的卡看,取其中的最小值,即为答案。

二分出距离,要判断用这个距离的卡,能否在规定时间内到达终点,这里用单调队列优化dp,时间复杂度为O(nlogn)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll price[100010];//price[i]表示 能走的距离的最大值为i的票的价格 
ll minute[100010];//进入该第i个地铁站所花费的时间 
ll dp[100010];//dp[i]指花费的时间
ll que[100010];//单调队列
ll head,tail;//队列的头下标和队列的尾下标 
ll n,t;//地铁站的个数,容许花费的最大时间。

bool check(ll L)
{
	head=1,tail=1;//头尾都是1 
	que[head]=1;
	dp[1]=0;
	
	//单调队列的基本操作 
	for(int i=2;i<=n;i++)//遍历每一个距离
	{
		while(tail<head && i-que[tail]>L)//当 i 到尾的距离大于假定的最短距离 ,尾往前走 
			tail++;
		
		dp[i]=dp[que[tail]]+minute[i];//来到上一个位置(尾)所花费的时间加上到i花费的时间 
		que[++head]=i;//在队列中加入当前地铁站 
		
		while(tail<head && dp[que[head]]<=dp[que[head-1]])// 维护单调队列,将头后比头大的弹掉,直到从尾到头是单调递增的。 
		{
			que[head-1]=que[head];
			head--; 
		}
	} 
	return dp[n]<=t;//如果花费的时间比给的时间小,那么再往更小的距离所在的区间搜 ,r=mid-1; 
}

int main()
{
	/*
		 二分出L,L是卡能走的最短的间隔距离, 
		 然后在>=L里选择一个最低价格即可
		 二分里面用单调队列优化
		 复杂度O(NlogN).
	*/
	//freopen("journey.in", "r", stdin);
	//freopen("journey.out","w",stdout);
	
	scanf("%lld %lld",&n,&t);	t-=n-1;
	for(int i=1;i<=n-1;i++)		scanf("%lld",&price[i]); 
	for(int i=2;i<=n-1;i++)		scanf("%lld",&minute[i]);
	
	ll l=1,r=n-1,mid,mn;//mn是L的最小值 
	while(l<=r)//用二分求出最小距离 
	{
		mid=(l+r)/2;
		if(check(mid))//用单调队列优化 
		{
			mn=mid;
			r=mid-1;
		}
		else
			l=mid+1;
	}
	ll ans=price[mn];
	
	for(int i=mn+1;i<n;i++)	ans=min(price[i],ans);
	
	printf("%lld\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值