• 浅谈单调队列优化DP


    这篇是搬运自己在洛谷写的题解
    题目链接:(luoguP1725)
    相信读完题就能看出这是一道简单的DP题

    @

    状态转移

    状态转移方程很容易想到。

    即:

    dp[ i ] = max{区间内的最大dp值}+该点的权值

    然而这种算法的最坏复杂度为(O(n^2)),而本题的数据是(1e5)级别的,这样的复杂度显然不正确,必须优化。


    优化

    哪一步可以优化呢?

    可以发现这样转移有着冗杂的枚举区间内元素的过程。

    我们又发现每次跳的区间都是一个固定长度,自然而然地想到了一个经典的问题:滑动窗口问题,即单调队列,可以让我们做到(O(n))预处理,(O(1))找到任意固定长度区间内的最值。

    有了单调队列,我们的dp过程可以省去枚举区间内的每个元素的过程,总复杂度也由(O(n^2))降到(O(n)),完全没有压力。


    如何实现

    在代码中由注释进行讲解:

    #include<cstdio>
    using namespace std;
    #define oo 0x3f3f3f3f 
    #define ri register int
    const int N = 200005;
    int n,l,r,head = 1,tail = 0,cur = 0,ans = -oo,a[N],q[N],dp[N];
    //head,tail分别是单调队列的首尾指针,cur是指向当前待入队列的元素,a存权值,q为单调队列(手打) 
    inline int max( int a , int b ){return a > b ? a : b; }//手打max 
    template<class T>
    inline void read(T &res){
        static char ch;T flag = 1;
    	while( ( ch = getchar() ) < '0' || ch > '9' ) if( ch == '-' ) flag = -1;
    	res = ch - 48;
    	while( ( ch = getchar() ) >= '0' && ch <= '9' ) res = res * 10 + ch - 48;
    	res *= flag;
    }//快读 
    int main()
    {
        read( n );read( l );read( r );
        for( ri i = 0 ; i <= n ; i++ ) read( a[ i ] );
        for( ri i = 1 ; i <= n ; i++ ) dp[ i ] = -oo;//初始化 
        for( ri i = 1 ; i <= n ; i++ ){
        	//由于一个点可到达的区间为[i+l,i+r],因此可以到达一个点的区间为[i-r,i-l],注意不要越界 
        	while( i - cur >= l ){//让能够入队的结点入队 
        		while( head <= tail && dp[ cur ] >= dp[ q[ tail ] ] ) tail--;
    			//由于单调队列是单调递减的,所以我们要删除队尾那些dp值小于待入队结点dp值的结点 
    			q[ ++tail ] = cur++;//入队 
        	}
        	while( head <= cur && i - q[ head ] > r ) head++;
    		//如果队列的头已经不再界限内,则不可能再更新当前 
        	if( head <= tail )//注意,当队列不为空时才可以转移 
    		  dp[ i ] = dp[ q[ head ] ] + a[ i ];
        }
        //因为题目说只要下一步的位置编号大于N就算到达对岸 
    	//所以最后得出答案,为区间[n-r+1,n]中的dp最大值 
        for( ri i = n ; i >= n - r + 1 ; i-- )
    	  ans = max( ans , dp[ i ] );
        printf( "%d
    " , ans );
    	return 0;
    }
    

    如果嫌这道题太简单,可以尝试(P3957) 跳房子

  • 相关阅读:
    响应式设计的 5 个 CSS 实用技巧
    iframe的高度自适应的方法
    HDOJ1285 比赛排名(拓扑排序)
    GENIA项目GENIA语料库
    HDOJ1102 修路问题(最小生成树Prim)
    二叉树的一些操作
    GENIA项目综述论文(E99)
    GENIA项目主页
    读《统计自然语言处理》有笔记——语料库与知识词汇库
    HDOJ2535 ( Vote ) 【水题】
  • 原文地址:https://www.cnblogs.com/hzyhome/p/11658248.html
Copyright © 2020-2023  润新知