BZOJ3830: [Poi2014]Freight

111 篇文章 0 订阅
26 篇文章 0 订阅

题目大意:有两个城镇,从A到B需要的时间为S,然后有N辆列车需要从A到B再回来,任何时刻铁路上只能有向着同一个方向前进的列车,然后每辆列车有一个从A出发的最早出站时间,问所有列车全部回到A站的最早时间

首先经过分析可以得出,这些列车是分批行进的,就是一批列车从A到B再回来,然后下一批列车再走...一定不会出现某辆列车在某一批到了B而留在那里没有跟着下一波回A的浪潮回来而留守B地等待下一次的情况,因为这样和跟在这一批的末尾回来是等价的

所以我们就可以开始DP了,Fi表示前i辆车分了几批之后,最后一辆车回来的最早时间.Ti表示这辆车最早出发的时刻

然后可以得到DP式

Fi=min ( max( Fj+i-j-1 , T(i) )+2*S+i-j-1) )

整理一下可以得到

Fi=min ( max( Fj-j-1 , T(i)-i )+2*S-j-1) )

因为Fi-i是单调不降的,所以max( Fj-j-1 , T(i)-i )是一个一开始等于Ti-i,后来单调递增的函数

我们可以二分这个位置,前面的用Ti-i+2*S-j-1来更新答案,那Fi取最小值时j肯定在二分的临界点那里

后面的会用Fj-2*j+2*S-2来更新答案,我们可以倒着用树状数组存起来,然后查询即可

总时间复杂度O(NlogN)


#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000010
using namespace std;
long long a[N],f[N];
long long c[N];
long long n,s;
void change(long long x,long long v)
{
	for(;x<=n;x+=x&-x)
	c[x]=min(c[x],v);
}
long long check(long long x)
{
	long long ans=707185547707185547LL;
	for(;x;x-=x&-x)
	ans=min(ans,c[x]);
	return ans;
}
int main()
{
	scanf("%lld%lld",&n,&s);
	long long i,j;
	scanf("%d",&a[1]);
	for(i=2;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		a[i]=max(a[i-1]+1,a[i]);
	}
	long long L,R,mid;
	memset(c,0x3f,sizeof(c));
	for(i=1;i<=n;i++)
	{
		L=1;R=i;
		while(L<R)
		{
			mid=(L+R)>>1;
			if(f[mid]-mid-1<=a[i]-i) L=mid+1;
			else R=mid;
		}
		f[i]=a[i]-(L-1)+2*s+i-1;
		if(L!=i) f[i]=min(f[i],check(n+1-L)+2*s+2*i);
		change(n+1-i,f[i]-2*i-2);
	}
	printf("%lld",f[n]);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值