1. 程式人生 > 實用技巧 >2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest J - Journey to the "The World's Start"

2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest J - Journey to the "The World's Start"

題意:一共n個站,首先處於第一個站的乘車點,在不用卷的情況下,會花一分鐘時間到下一站i+1站下車點,同時要花d[i]分鐘到i+1站的乘車點,在用卷的情況下,假如用的是第r張卷,可以從i搭到i-r到i+r範圍內的所有站臺,乘車時間不能省略,但是跑去乘車點的時間可以省略,第r張卷需要p[r]元,一張卷可以用多次,問買哪一張卷可以在t時間內到達第n個站臺。
題解:因為用第r張卷的時間一定要大於等於用r+1張卷的時間,所有可以二分用哪張卷,設dp[i]為到達第i站乘車點用的最短時間,dp[i]可以由i-r到i-1的dp的最大值得到,用雙指標維護一下遞減序列,與i距離大於r的踢出,頭部比dp[i]值小的踢出,最後可得到dp[n]
http://codeforces.com/gym/100801

#include<stdio.h>
#include<algorithm>
using namespace std;
#define LOCAL
#define ll long long
ll p[50100],d[50100];
ll dp[50100],que[50100];
ll n,t;
int check(int k){
	dp[1]=0;
	que[1]=1;
	int head=1,tail=1;
	for(int i=2;i<=n;i++){
		while(head>tail){
			if(i-que[tail]<=k)break;
			tail++;
		}
		dp[i]=dp[que[tail]]+d[i];
		while(head>=tail){
			if(dp[que[head]]<dp[i])break;
			head--;
		}
		que[++head]=i;
		//printf("que[head]=%d que[tail]=%d dp[%d]=%d\n",que[head],que[tail],i,dp[i]);
	}
	if(dp[n]+n-1>t)return 0;
	else return 1;
}
int main(){
	#ifdef LOCAL
    freopen("journey.in","r",stdin);
	freopen("journey.out","w",stdout);
#endif
	scanf("%lld %lld",&n,&t);
	for(int i=1;i<n;i++){
		scanf("%lld",&p[i]);
	}
	for(int i=2;i<n;i++)scanf("%lld",&d[i]);
	ll ans=n-1;
	ll l=1,r=n-1;
	//printf("%d\n",check(2));
	while(l<=r){
		int mid=(l+r)/2;
		if(check(mid)==1){
			ans=mid;
			r=mid-1;
		}
		else{
			l=mid+1;
		}
	}
	ll res=100010;
	for(int i=ans;i<n;i++)res=min(res,p[i]);
	printf("%lld\n",res);
}