链接
https://www.luogu.org/problemnew/show/P1440
大意
输入一个长度为 的序列,给定一个 ,设 求出所有的
思路
毫无疑问, 必定等于0,因为1前面的最小值就是0,那么我们怎么考虑剩下的呢?
的范围决定了我们不能使用暴模,一种想法是我们每次新增一个就去比较一下是否大于最小值,然后放入。但是这种算法显然没有考虑到之前的因素,因为当 的时候,就要去掉第 个,如果直接去掉的话可能导致整个数组发生变动,使得答案不满足最优性
我们可以通过单调队列+结构体去解决这个问题,具体怎么实现呢?我们看下面的思路
给定这个单调队列每个元素都有两个下标 和 ,分别表示当前元素出现的顺序以及其值。
对于每个新增进来的元素,我们给予插队,将其放入单调队列中
然后维护这个队列,当队首(也就是最大值)的编号大于等于 时,也就是不满足前 个时,将其弹出队列。
这样,此队列的队首一定是前 个数的最小值
代码
#include<deque>
#include<cstdio>
using namespace std;
struct node{int id,nu;};
deque<node>q;
int n,m,f,a[2000001];char c;
int read()
{
f=0;
while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return f;
}
void write(int x){if(x>9)write(x/10);putchar(x%10+48);return;}
int main()
{
n=read();m=read();putchar(48);putchar(10);
for(int i=1;i<n;putchar(10),i++)
{
a[i]=read();
while(q.size()&&a[i]<q.back().nu) q.pop_back();//予以插队
q.push_back(node{i,a[i]});//将其放入
while(i-q.front().id>=m) q.pop_front();//维护
write(q.front().nu);//输出
}
}
代码2
其实代码1的基础上可以去掉结构体,因为 是可以表示 的,所以就可以去掉 ,得到下面这个代码
#include<deque>
#include<cstdio>
using namespace std;
deque<int>q;
int n,m,f,a[2000001];char c;
int read()
{
f=0;
while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return f;
}
void write(int x){if(x>9)write(x/10);putchar(x%10+48);return;}
int main()
{
n=read();m=read();putchar(48);putchar(10);
for(int i=1;i<n;putchar(10),i++)
{
a[i]=read();
while(q.size()&&a[i]<a[q.back()]) q.pop_back();
q.push_back(i);
while(i-q.front()>=m) q.pop_front();
write(a[q.front()]);
}
}