众所周知
动态规划 的 题
往往 推了a long time
但是o(n^3)
于是就自闭了
所以我们有了
单调队列和栈
这种东西
神奇的单调队列
朴素 o(n^2)
乱搞 o(nlog n)
(线段树、RMQ)
然后。。。
单调队列
o(n)
对,你没有看错,
就是一遍 其实是o(2n)?!
单调队列
用一个东西(栈、队列、数组。。。随君所好)
然后,
解释都在注释里
#include <cstdio>
using namespace std;
const int MAXN = 1000001;
int num[MAXN],q[MAXN],it[MAXN],q1[MAXN],it1[MAXN];
/*要求最大和最小,q-min,q1-max
it&&it1记录q和q1中元素原来所在位置
num记录读入的值
*/
int ALL,Begin,End,Begin1,End1,pr[MAXN];
/*
ALL充当二次输出的Index,pr则记录二次输出的值
Begin,End记录q的队首&&队尾
Begin1,End1记录q1的队首&&队尾
*/
int main()
{
int n,k,i;
scanf("%d%d",&n,&k);
for(i = 1;i <= n;i++)
scanf("%d",&num[i]);
//读入
for(i = 1;i <= n;i++)
{
if(Begin == 0)
{
++Begin,++End;
q[Begin] = num[i];
it[Begin] = i;
++Begin1,++End1;
q1[Begin1] = num[i];
it1[Begin1] = i;
//其实上面这一步无必要
} else {
while(q[End] >= num[i]&&End >= Begin)
--End;
/*当q的队尾元素大于此时要处理的num[i]
因为q-min
所以此时q的队尾元素以后绝不会再用到
*/
End++;
//加之前的End是不满足q[End] >= num[i]&&End >= Begin
q[End] = num[i];
it[End] = i;
//记录对应的值
while(q1[End1] <= num[i]&&End1 >= Begin1)
--End1;
End1++;
q1[End1] = num[i];
it1[End1] = i;
//同求MIN,符号 反一下
}
//这样处理后q的队首一定min,q1一定max
if(i >= k)
{
//符合题意,可以输出了
while(it[Begin] < i - k + 1)
Begin++;
//如果q此时队头不在范围中
while(it1[Begin1] < i - k + 1)
Begin1++;
//同上
ALL++;
//记录二次输出的值
pr[ALL] = q1[Begin1];
printf("%d ",q[Begin]);
}
}
putchar('
');
//putchar常数优化,然而并没有什么用
for(i = 1;i <= ALL;i++)
printf("%d ",pr[i]);
}
又一道稍微难一点的题
Max Sum of Max-K-sub-sequence
单调队列与dp的关系
一道例题
瑰丽华尔兹
在一个状态转移方程中
dp[][][][]..[]= ....
在一定条件下可以将最后一维压缩成单调队列