牛牛的滑动窗口
题面
链接:https://ac.nowcoder.com/acm/contest/7604/D
牛牛最近学习了滑动窗口类的算法,滑动窗口算法可以解决一些线性数组的离线静态区间查询类问题。
具体来说,假设对于一个数组进行m次静态区间查询问题。如果这些查询满足条件:
接下来只要查询的问题满足可以快速插入和删除单点,就可以使用滑动窗口优化,将这m次查询的复杂度降低到O(n)。
牛牛接下来想要问你的问题也和定长滑动窗口有关。
众所周知,长度为k的滑动窗口从左到右去截取一个长度大小为n的数组时,一共可以截取到n-k+1个子数组。
牛牛将这n-k+1个子数组的极大值与极小值的乘积求和称为该数组的"第k窗口值"。
举个例子,假设长度为5的数组为[1,5,2,4,3],长度为3的滑动窗口可以截取三个子数组,它们分别为[1,5,2],[5,2,4],[2,4,3]。
所以该数组的“第3窗口值”为1*5+2*5+2*4=23。
对于一个给定大小的数组n,牛牛现在想要知道它的第1,2,3,4,5...n窗口值各是多少,请你编写程序解决他的问题。
解法
朴素的算法就是用单调队列
但很显然这个算法过不了,原因在于
比如样例
5
1 5 2 4 3
可以发现区间[1 5]、[1 5 2]、[1 5 2 4]、[1 5 2 4 3]它们的贡献都是
于是想到先固定左端点,然后再统计一些右端点的答案。
假如当前固定左端点为i,而i后面第一个比
然后继续往后扫描,重复比较即可。
#include<cstdio>
#include<stack>
#define ll long long
//#define zczc
using namespace std;
const int N=100010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
wh*=f;return;
}
inline int min(int s1,int s2){
return s1<s2?s1:s2;
}
inline int max(int s1,int s2){
return s1<s2?s2:s1;
}
int m,a[N];
#define lowbit (wh&-wh)
ll t[N];
inline void ch(int wh,ll val){
for(;wh<=m;wh+=lowbit)t[wh]+=val;
}
inline void change(int l,int r,ll val){
//printf("change:%d %d %lld\n",l,r,val);
ch(l,val);ch(r+1,-val);return;
}
inline ll work(int wh){
ll an=0;
for(;wh;wh-=lowbit)an+=t[wh];
return an;
}
#undef lowbit
struct node{
int num,data;
};
stack<node>st;
int firmin[N],firmax[N];
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);
for(int i=1;i<=m;i++)read(a[i]);
firmin[m+1]=firmax[m+1]=m+1;
st.push((node){m+1,101});
for(int i=m;i;i--){
while(st.top().data<=a[i])st.pop();
firmax[i]=st.top().num;
st.push((node){i,a[i]});
}
while(!st.empty())st.pop();
st.push((node){m+1,0});
for(int i=m;i;i--){
while(st.top().data>=a[i])st.pop();
firmin[i]=st.top().num;
st.push((node){i,a[i]});
}
for(int i=1;i<=m;i++){
int nl=i,lmax=firmax[i],lmin=firmin[i],nmax=a[i],nmin=a[i];
while(nl<=m){
change(nl-i+1,min(lmax,lmin)-i,(ll)nmax*nmin);
nl=min(lmax,lmin);
if(lmin<lmax){
nmin=a[lmin];
lmin=firmin[lmin];
}
else{
nmax=a[lmax];
lmax=firmax[lmax];
}
}
}
for(int i=1;i<=m;i++)printf("%lld ",work(i));
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析