小鸟(单调队列加DP)

有一排n棵树,第i棵树的高度是Di。 一群小鸟要从第1棵树飞到第n棵树去玩。
不同小鸟的飞跃能力不同,第i只小鸟的飞跃能力为ki,表示如果当前它位于第x号树,那么它可以飞到x+1,x+2,……,x+ki号树上去,也就是一次可以飞过ki棵树。
如果小鸟飞到一棵不矮于当前树的树,那么他的劳累值会+1,否则不会。 小鸟们希望最小化劳累值,请你计算每只小鸟达到终点所需最小劳累值。

题解

考虑到当前状态对以后的状态没有影响,所以只需要考虑通过之前的最优状态转移即可,此值是递增的所以考虑用单调队列优化。

代码

//单调队列优化DP 
#include
#include
#include
#include
#include
#include
#define inf 1e9
using namespace std;
inline void _read(int &x){ 
    char t=getchar();bool sign=true; 
    while(t<'0'||t>'9') 
    {if(t=='-')sign=false;t=getchar();} 
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0'; 
    if(!sign)x=-x; 
}
const int maxn=100005;
int n,q,cap;
int f[maxn],h[maxn];
int main(){
//  freopen("bird.in","r",stdin);
//  freopen("bird.out","w",stdout); 
    int i,j,k,temp;
    cin>>n;
    for(i=1;i<=n;i++)_read(h[i]);
    cin>>q;
    while(q--){
        deque<int> q;
        _read(cap);
        q.push_back(1);
        for(i=2;i<=n;i++){
            f[i]=inf;
            while(q.size()&&i-q.front()>cap)q.pop_front();
            if(h[q.front()]<=h[i])f[i]=f[q.front()]+1;
            else f[i]=f[q.front()];
            while(q.size()&&(f[i]h[q.back()])))q.pop_back();
            q.push_back(i);
        }
        printf("%d\n",f[n]);
    }

}

你可能感兴趣的:(小鸟(单调队列加DP))