单调队列的应用:查询定长区间的最小值或者最大值,相对于RMQ来说是线性级别的算法。
单纯的单调队列实现起来就那两行,相当简单,比较复杂的是用单调队列的定区间查询功能优化dp以及其他算法。
单调队列优化dp的典型例子:
单调队列优化多重背包。
完成这个优化的前提是要对状态转移方程进行一定的变换,这里面包含的思维过程往往比单调队列本身复杂得多。
单调队列优化的多重背包复杂度:O(nm)
考虑把O(c )的转移压缩为O(1)
变形:
a=j/w[i]
b=j%w[i]
j=b+aw[i]
思路:承重为j时,不考虑ci限制时最多选a个i号元素。假设a个中不选k个,即选a-k个。
f[i][b+0*w[i]]=max(f[i-1][b+0*w[i]]-0*v[i])+0*v[i];
f[i][b+1*w[i]]=max(f[i-1][b+0*w[i]]-0*v[i],f[i-1][b+1*[w[i]])-1*v[i])+1*v[i];
f[i][b+2*w[i]]=max(f[i-1][b+0*w[i]]-0*v[i],f[i-1][b+1*[w[i]])-1*v[i],f[i-1][b+2*w[i]]-2*v[i]])+2*v[i];
....
f[i][b+k*w[i]]=max(f[i-1][b+0*w[i]]-0*v[i],f[i-1][b+1*[w[i]])-1*v[i],f[i-1][b+2*w[i]]-2*v[i]]....f[i-1][b+a*w[i]]-k*v[i])+k*v[i];
....
f[i][b+a*w[i]]=max(f[i-1][b+0*w[i]]-0*v[i],f[i-1][b+1*[w[i]])-1*v[i],f[i-1][b+2*w[i]]-2*v[i]]....f[i-1][b+a*w[i]]-a*v[i])+a*v[i];
还要注意一个细节:对于个数的选择与k无关,而与队列中k的跨度有关,因为选择多少个是j中数值的变化。
再添加一个例题:
这道题咋一看异常抽象完全找不到思路,然而仔细一分析,还是可以通过dp解决的,这就是dp的玄学和神奇之处。