Luogu-P1886 滑动窗口
题目
测试得分: 100
主要算法 : 单调队列优化DP
题干:
单调队列优化DP板子
分析
单调队列优化DP定长连续区间最值问题
代码
#include<stdio.h> #include<stdlib.h> #define FORa(i,s,e) for(int i=s;i<=e;i++) #define FORs(i,s,e) for(int i=s;i>=e;i--) #define gc getchar()//pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),stdin)?EOF:*pa++ #define File(name) freopen(name".in","r",stdin);freopen(name".out","w",stdout); using namespace std; char buf[100000],*pa,*pb; inline int read(); const int N=1e6,K=1e6; int n,k,a[N+1]; int head,tail,num[K+1],q[N+1]; /*单调队列,num[]记录的是单调队列中元素在输入数据中的编号,q代表的是元素在输入数据中的值*/ void Solve_Min() { head=1,tail=0; FORa(i,1,n) { while(head<=tail&&a[i]<q[tail]) tail--; /*如果发现单调队列中(简单的说就是这个框中的所有元素)有比现在还大的,全部删除 删除理由是单调性性质,这个答案对于后面没有贡献了,因为现在这个即将插入的元素即将做出贡献 做的贡献越多而且做贡献的次数也绝对不低于这些删除的元素 */ q[++tail]=a[i],num[tail]=i; //将元素插入队列 while(num[head]<i-k+1) head++;//如果单调队列中首尾元素的差值超过了框的长度,推进头指针 if(i>=k) printf("%d ",q[head]);//满足条件输出 } printf("\n"); } void Solve_Max() { head=1,tail=0; FORa(i,1,n) { while(head<=tail&&a[i]>q[tail]) tail--; q[++tail]=a[i]; num[tail]=i; while(num[head]<i-k+1) head++; if(i>=k) printf("%d ",q[head]); } } int main() { n=read(),k=read(); FORa(i,1,n) a[i]=read(); Solve_Min(),Solve_Max(); return 0; } inline int read() { register char c(gc);register int f(1),x(0); while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc; while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc; return x*f; }
总结:
确定动规模型