题目要求:一般和dp一样,不过用普通dp会T,其中dp有一维可以用单调队列优化
可以用单调队列优化的数值会出现明显的上位替代,比如:最近的最大值,最近的最大总和,耀骑士(不是)。
例子:1.输入一个长度为 n 的整数序列,从中找出一段长度不超过 m 的连续子序列,使得子序列中所有数的和最大。
原本暴力复杂度O(nm),但是由前缀和s[i]-s[j]发现,在i固定的情况下,s[j]越小越好,并且离i越近越好,这样就出现了上位替代。可以用单调队列优化。
2.农场有编号连续的n头奶牛,每头奶牛i有一个效率Ei,不能选择k头以上连续的奶牛,问最大效率。
易得,f[i]= f[i-j-1]+s[i]-s[i-j],可以发现,在i固定的情况下,f[i-j-1]-s[i-j],越大越好,并且离i越近越好,于是用单调队列优化(i-j范围(i-k~i),于是用单调队列存上位的i)
3.有按顺序排列的n个地方,初始没油,给定每个点的油,和到下一站需要的油,问从每个点出发,能不能环绕一圈(i~i+n)
令 本地油[i]-下一站花油[i]的前缀和为s[i],从i开始的一段路,剩油为s[i~i+n]-s[i-1],可用单调队列存s[i~i+n]的最小值s[k],诺s[k]-s[i-1]>=0则可以绕一圈
4.给a*b的矩阵,问n*n的范围里的max减min的最小值为多少?
预处理,对行,单调队列处理mx[i]为mx[i~i-n]范围里的最大值,对mx[i]按列处理一次,得n*n的最大值,复杂度O(a*b),最小值同理,就可得答案。
int q[N];
void get_min(int a[], int b[], int tot)
{
int hh = 0, tt = -1;
for (int i = 1; i <= tot; i ++ )
{
if (hh <= tt && q[hh] <= i - k) hh ++ ;
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;
b[i] = a[q[hh]];
q[ ++ tt] = i;
//b[i] = a[q[hh]];也可能在这里
}
}