猴子

一.题目大意

   有Q只猴子要从第一棵树到第n棵树去,第i只猴子一次跳跃的最远距离为Ki。如果它在第x棵树,那它最远可以跳到第x+Ki棵树。如果第j棵树的高度比第i棵树高或相等,那么它从第i棵树直接跳到第j棵树,它的劳累值会增加1。所有猴子一开始在第一棵树,请问每只猴子要跳到第n棵树花费的劳累值最小。

第一行一个整数n,表示有n棵树。(2<=n<=1000000)

接下来第二行给出n个正整数D1,D2,……,Dn(1<=Di<=10^9),其中Di表示第i棵树的高度。

第三行给出了一个整数Q(1<=Q<=25),接下来Q行,给出了每只猴子一次跳跃的最远距离Ki(1<=Ki<=N-1)。

这里说明一下: 4 6 3

若猴子在4,那它可以直接跳到3的那棵树

二.具体思路

   看到这道题很容易想到dp思想,首先我们可以进行q次循环,找出每只猴子跳到n的最小劳累值。

   我们定义dp[i]表示这只猴子跳到第i棵树的最小劳累值,状态转移方程就有:

   if(a[i]>=a[i-k])

        dp[i] = min(dp[i-k] + 1,dp[i])

   else 

       dp[i] = min( dp[i-k] , dp[i] )

其中0<=k<=k[i]

   但是由于数据很大,直接写二重会超时,于是可以用单调队列优化

  我们用单调队列保护i-k到i的递增性,最后只需要用队头去判断一次就行了

  但有一个问题:由于要涉及到+1的情况,怎样维护它呢?

   我们可以用贪心的思路想一下,如果最小值是唯一的,那么就算+1它也是最小值

  但如果不是的话,比如队列里的dp[1]与dp[2]相等,则我们就去找它们高度的较大值,因为从高处向低出跳不需要劳累值,高度越高,就越不容易加劳累值。

三.代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <deque>
using namespace std;
const int MAXN =1000003;
int n , k , dp[MAXN] , a[MAXN] , q , ans = 0x3f3f3f3f;
int main(){
    scanf( "%d" , &n );
    for( int i = 1 ; i <= n ; i ++ )
        scanf( "%d" , &a[i] );
    scanf( "%d" , &q );
    while( q-- ){
        scanf( "%d" , &k );
        deque<int>que;
        memset( dp , 0x3f , sizeof( dp ) );
        dp[1] = 0;
        que.push_back( 1 );
        for( int i = 2 ; i <= n ; i += 1 ){
            if( !que.empty() && que.front() + k < i )
                que.pop_front();
            dp[i] = dp[que.front()];
            if( a[i] >= a[que.front()] )
                dp[i] +=1;
            while( !que.empty() && ( dp[que.back()] >  dp[i]  ||  (dp[que.back()] == dp[i] && a[i] > a[que.back()] ) ) )
                que.pop_back();
            que.push_back( i );
        }
        printf( "%d\n" , dp[n] );
    }
    return 0;
}

   

 

   

猜你喜欢

转载自blog.csdn.net/weixin_43823476/article/details/85047765