P3580 [POI2014]ZAL-Freight(单调队列dp)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3580 [POI2014]ZAL-Freight(单调队列dp)相关的知识,希望对你有一定的参考价值。

P3580 [POI2014]ZAL-Freight(单调队列dp)

考虑两辆车怎么样是最优的。

t 1 , t 2 , S t_1,t_2,S t1,t2,S

t 1 + S t_1+S t1+S

第一辆车: [ t 1 , t 1 + S ] [t_1,t_1+S] [t1,t1+S]

假设第二辆车在某个时间 t i ∈ [ t 1 + 1 , t 1 + S ] t_i\\in [t_1+1,t_1+S] ti[t1+1,t1+S]出发。

在第一辆车到达到右端点后,必须等第一辆车过来才能继续接下来的行动。

所以第二辆车到达的时间是: t i + S t_i+S ti+S

此时第一辆车和第二辆车在右端点。

此时是回程是对称的,只不过是出发时间不同。

所以我们只需考虑往程最优即可。

因为相邻辆车至少间隔 1 1 1min,所以显然在 t i = t 1 + 1 t_i=t_1+1 ti=t1+1出发时最优的。

此时能最早到达。

因此考虑 d p dp dp转移。
f i = m i n ( f i , m a x ( a i , f j + i − j − 1 ) + 2 × S + i − j − 1 ) \\large f_i=min(f_i,max(a_i,f_j+i-j-1)+2\\times S+i-j-1) fi=min(fi,max(ai,fj+ij1)+2×S+ij1)
先去掉 m a x max max

分情况讨论: f j + i − j − 1 ≥ a i f_j+i-j-1\\ge a_i fj+ij1ai

即: f j − j ≥ a i − i + 1 \\large f_j-j\\ge a_i-i+1 fjjaii+1​。

因为 i , S i,S i,S​是定值,所以单调队列维护维护 f j − j f_j-j fjj的最小值即可。​​

答案为: f j + 2 × ( S + i − j − 1 ) f_j+2\\times (S+i-j-1) fj+2×(S+ij1)

否则: f j − j < a i − i + 1 f_j-j<a_i-i+1 fjj<aii+1

答案就是: a i + 2 × S + i − j + 1 a_i+2\\times S+i-j+1 ai+2×S+ij+1

此时的 j j j​就是单调队列最后一次弹出的位置。

时间复杂度: O ( n ) O(n) O(n)

// Problem: P3580 [POI2014]ZAL-Freight
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3580
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-26 19:24:10
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e6+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
int n;
ll s,f[N],a[N];
int q[N],l=1,r;
int main(){
	scanf("%d%lld",&n,&s);
	a[0]=-1;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]=max(a[i],a[i-1]+1);
	for(int i=1;i<=n;i++){
		while(l<=r&&f[q[l]]-q[l]<a[i]-i+1) l++;
		f[i]=a[i]+2*s+i-q[l-1]-1;
		f[i]=min(f[i],f[q[l]]+2*(s+i-q[l]-1));
		while(l<=r&&f[q[r]]-2*q[r]>f[i]-2*i) r--;
		q[++r]=i;
	}
	printf("%lld\\n",f[n]);
	return 0;
}

以上是关于P3580 [POI2014]ZAL-Freight(单调队列dp)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3831[Poi2014]Little Bird 单调队列

BZOJ 3524: [Poi2014]Couriers

POI2014

FarmCraft[POI2014]

[Poi2014]Couriers

[POI2014]KUR-Couriers