2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest Journey to the "The World's Start"
阿新 • • 發佈:2020-11-18
首先我們二分一個x,x是用的票能跳過x站,因為票可以多次使用,所以我們要dp當第i站能用票省下的時間p,只要p小於等於 (不用票的總時間-t)就好了
這個dp我們可以寫出轉移方程 dp[i]=\(max_{j=i-x}^{j=i}\)(d[j]+s[i]-s[j],(s是字首和)
但是這個dp是\(n^2\)的,所以我們需要用單調佇列優化
程式碼
#include<stdio.h> #define LOCAL #include<bits/stdc++.h> using namespace std; #define ll long long const int maxn = 1e5+10; ll p[maxn],d[maxn],a[maxn],dp[maxn],q[maxn];ll n,t,sum,mi=1e9; ll pd(ll mid) { memset(q,0,sizeof(q));ll l=1,r=0,mx=0; memset(dp,0,sizeof(dp)); q[++r]=1; for(ll i=2;i<=n;i++) { while(l<=r&&(i-q[l])>mid) l++; //printf("i=%lld q[%lld]=%lld\n",i,l,q[l]); dp[i]=dp[q[l]]+a[i-1]-a[q[l]]; mx=max(dp[i],mx); while(l<=r&&(dp[i]-a[i]>=dp[q[r]]-a[q[r]])) r--; q[++r]=i; //printf("dp[%lld]=%lld q[%lld]=%lld q[%lld]=%lld\n",i,dp[i],l,q[l],r,q[r]); } if(mx>=sum) return 1; return 0; } int main() { #ifdef LOCAL freopen("journey.in","r",stdin); freopen("journey.out","w",stdout); #endif scanf("%lld %lld",&n,&t); sum=n-1; for(int i=1;i<=n-1;i++) { scanf("%lld",&p[i]);mi=min(p[i],mi); } for(int i=2;i<=n-1;i++) scanf("%lld",&d[i]),sum+=d[i]; if(sum<=t) { printf("%lld\n",mi); return 0; } sum=sum-t; ll l=1,r=n-1,len=0; for(ll i=2;i<=n;i++) a[i]=a[i-1]+d[i]; //pd(1); while(l<=r) { ll mid=(l+r)/2; if(pd(mid)==1) { len=mid; r=mid-1; } else l=mid+1; } ll g=1e9; for(int i=len;i<=n-1;i++) g=min(g,p[i]); printf("%lld\n",g); //printf("sum=%d\n",sum); /*ll s=0,l=1,r=1; ll len = n+10; while(l<=r&&l<=n-1&&r<=n) { int flag=0; while(s<sum){ s+=1+d[r]; r++; if(r>n){ flag=1; break; } } if(flag==1)break; len=min(len,r-l); printf("s=%lld l=%lld r=%lld\n",s,l,r); if(l+1<r) s-=d[l+1]+1; else s--; l++; } printf("len=%lld\n",len); ll g = 1e9; for(ll i = len; i <= n-1; i++){ g=min(g,p[i]); } printf("%lld\n",g);*/ } /* 4 4 1 2 3 1 4 6 6 1 4 5 5 6 7 1 5 6 */