题解 P3572 【[POI2014]PTA-Little Bird】

· · 题解

题目大意

鸟要飞过树林,每次只能飞一段,长度有限制,停靠在树上

如果这棵树比刚才的矮,无论中间有多高的屏障,不用耗费体力,否则耗费体力1

问:最开始在树1,飞到树n,需要多少体力

解题思路

观察数据范围,明显是要O(qn)的算法

首先会每次询问分别处理,不难得到dp的状态转移方程

F_i=min(a_j>ai?f_j:f_j+1) 这个算法是$O(qn^2)$的,肯定会$TLE$,考虑优化 我们可以发现每次要转移的区间是**连续且单调的** 因此可以使用单调队列优化 这个优化要考虑$2$个因素(满足前面的前提下再考虑后面的) 1. $F_i$单调不下降 2. $a_i$单调上升 - 还要记得一句话:**如果一个选手比你小,还比你强,你就可以退役了**,这句话很多单调队列都用得上 ### 代码 ```cpp #include <cstdio> int n,m,x,head,tail,a[1000001],q[1000001],f[1000001]; int read(){ char ch=getchar();int res=0,w=1; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {res=res*10+ch-'0';ch=getchar();} return res*w; } int main(){ n=read(); for(register int i=1;i<=n;i++) a[i]=read(); m=read(); while(m--) { x=read();head=tail=1;q[tail]=1; for(register int i=2;i<=n;i++) { while(head<=tail&&i-q[head]>x) head++; if(a[q[head]]>a[i]) f[i]=f[q[head]]; else f[i]=f[q[head]]+1; while(head<=tail&&(f[q[tail]]>f[i]||(f[q[tail]]==f[i]&&a[q[tail]]<=a[i]))) tail--; q[++tail]=i; } printf("%d\n",f[n]); } return 0; } ```