单调队列优化的DP

(持续更新中……)

一、浅谈单调队列之多重背包

  前言:首先标题起了一个很优雅的名字,貌似很高深的样子,其实不然,只是把自己理解的记录一下而已。

多重背包的状态转移方程:dp[ i ]  [ j ]  =  max ( dp[ i - 1 ] [ j ]  , dp[ i - 1 ] [ j - k * v[ i ] ] + k * w[ i ]  } (  0 <= k <= num[ i ])  ; 

先说一下多重背包的二进制解法,因为大多数的题目都可以用此方法解决:复杂度( num[ i ] 为每类物品的个数)。

void Multip(int v ,int w ,int n) // v 为体积,w 为价值 ,n 为个数
{
    for(int i = 1 ;i <= n ;i <<= 1)
    {
        V[num] = i*v ;
        W[num++] = i*w ;
        n -= i ;
    }
    if(num)
    {
        V[num] = i*v ;
        W[num++] = i*w ;
    }
}

单调队列解法:

可以先看下这个博客 ,看几次后你就会理解它的思想了。这里再说一下我的理解。

当你在拿一件物品的时候,如果你细心推一下你会发现只有 j % v  余数相同的时候是有关联的,余数如果不相同是相互独立的( j 指当前要计算的体积,v 指当前物品的体积) 。

这里假设余数为 1 的情况,num = 2 ,体积为 v ,价值为 w .C (总体积)  = 8* v

dp  的时候只有这些情况

dp( 1 )  , dp( v  +  1 )  , dp( 2 * v + 1 )  ,  dp( 3 * v + 1 )  , dp( 4 * v  + 1 )  , dp( 5 * v  + 1 )  ,  dp( 6 * v + 1 )  ,  dp( 7 * v  + 1 )

那么 : dp( 2 * v + 1 )  = max { dp( 2 * v + 1 )   , dp( v + 1 )  + w , dp( 1 )  +  2 * w  }

dp(3 * v + 1)  = max { dp( 3 * v  + 1 )  , dp( 2 * v + 1 )  + w , dp( v + 1)  + 2 * w }

dp(4 * v + 1)  = max { dp ( 4 * v + 1 ) , dp( 3 * v + 1 )  + w ,dp( 2 * v + 1) + 2 * w }

dp(5 * v + 1)  = max { dp( 5 * v + 1 )  , dp( 4 * v + 1 )  +  w , dp( 3 * v + 1 )  + 2 * w }

dp(6* v + 1)  = max { dp( 6 * v + 1 )  , dp( 5 * v + 1 )  + w , dp( 4 * v + 1 )  + 2 * w }

dp(7 * v + 1)  = max { dp( 7 * v + 1)  , dp( 6 * v + 1)  + w  , dp( 5 * v + 1) + 2 * w }

每项都是有后面两项递推而来,这样还看不出什么规律的话让我们再变化一下:

让第一行减  2 * w  , 让第二行减 3 * v ,让第三行减 4 * v ……

得到:

dp( 2  * v + 1 )  = max { dp( 2 * v  + 1 )  - 2 *  w , dp( v  + 1 )  -  w  , dp( 1 )  }  + 2  *  w  ;

dp(3 * v + 1) = max {  dp ( 3 * v + 1 ) - 3 * w , dp ( 2 * v + 1 )  -  2 * w  , dp( v + 1 ) -   w }  + 3 * w  ;

dp(4 * v + 1) = max { dp ( 4 * v + 1) - 4 * w , dp(3 * v + 1 )  - 3 * w  , dp( 2 * v + 1)  -  2 * w }  + 4 * w  ;

dp(5 * v + 1)  = max { dp( 5 * v + 1 )  -  5 * w , dp( 4 * v + 1 )  -  4 * w , dp( 3 * v + 1 )  - 3 * w } + 5 * w ;

dp(6* v + 1)  = max { dp( 6 * v + 1 )  - 6 * w , dp( 5 * v + 1 )  - 5 * w , dp( 4 * v + 1)  - 4  * w }  + 6  * w  ;

dp(7 * v + 1)  = max{ dp( 7 * v + 1 )  - 7 * w , dp( 6 * v + 1)  - 6 * w , dp( 5 * v  + 1)  - 5 * w }  + 7 * w  ;

这样变化后明显看出有许多重复的,这样我们可以他们放在一个队列里,然后 每个数只进队列一次。

这样剩下的就是怎样维护队列了:

( 1 ) 删除小于等于当前入队的元素的值。

( 2 ) 删除无效元素,因为如果物品的件数只有 3 件物品,那么,滑动窗口里就只能放 3 个元素,多了的就是无效的元素。

代码~~>

还有一种特殊情况:当 V = W 的时候,只要判断队列中是否有装满的情况就可以了,因为如果某个体积成立,它加上在 k * v 都是可以装满的。这样只要判断当前队列中是否有装满的就可以了。

代码~~>

时间: 2024-08-30 03:47:45

单调队列优化的DP的相关文章

AcWing - 332 - 股票交易 = 单调队列优化dp

https://www.acwing.com/problem/content/334/ 第一次写单调队列优化的dp,首先朴素的做法不难想到,就是复杂度 \(O(n^3)\) ,然后考虑优化. 每天都从 \(pre=max(0,i-w-1)\) 天转移过来就刚刚好了. 考虑每个k是怎么更新j的. 买入股票: \(dp[i][j]=max\{dp[pre][k]-(j-k)*AP_i\;|\;k \leq j\;and\;(j-k) \leq AS_i\}\) \(dp[i][j]=max\{dp[

[Vijos 1243]生产产品(单调队列优化Dp)

Description 在经过一段时间的经营后,dd_engi的OI商店不满足于从别的供货商那里购买产品放上货架,而要开始自己生产产品了!产品的生产需要M个步骤,每一个步骤都可以在N台机器中的任何一台完成,但生产的步骤必须严格按顺序执行.由于这N台机器的性能不同,它们完成每一个步骤的所需时间也不同.机器i完成第j个步骤的时间为T[i,j].把半成品从一台机器上搬到另一台机器上也需要一定的时间K.同时,为了保证安全和产品的质量,每台机器最多只能连续完成产品的L个步骤.也就是说,如果有一台机器连续完

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

hdu3401 Trade(单调队列优化dp)

Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4734    Accepted Submission(s): 1587 Problem Description Recently, lxhgww is addicted to stock, he finds some regular patterns after a few d

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

woj 1575 - Signal generators 单调队列优化dp + 瞎搞

戳这里:1575 题意:直线上排列着N个信号发射器,每个信号发射器被激活后将会使得影响范围内的所有发射器都被激活.询问激活任意一个发射器后被激活的发射器数最大是多少. 官方题解:可能会存在环的情况,考虑按坐标排序后i < j < k,j激活了k,然后k再激活i.但是这样可以转化为直接激活k的方案.所以无影响. 于是可以用dp求解.dp[i] = max( dp[j] + 1 ), position[j] + R[i] >= position[i],用单调队列优化时间复杂度为O(n). 向

bzoj1855: [Scoi2010]股票交易--单调队列优化DP

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int

BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP

先建出广义后缀自动机. 然后跑出文章中每一个位置的最大匹配距离. 然后定义$f[i]$表示匹配到以$i$结尾的串时,最长的匹配距离. 显然可以二分$L$的取值. 然后容易得到$DP$方程 $f[i]=max(f[i-1],f[j]+i-j)(j<=i-L)$ 然后就发现$j$属于一个区间,然后就可以单调队列优化了. #include <map> #include <ctime> #include <cmath> #include <queue> #in

1855: [Scoi2010]股票交易[单调队列优化DP]

1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status][Discuss] Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=