想做这道题,我们首先需要知道一个容器——deque
deque:双端队列,顾名思义就是可以再两边操作的队列。
deque特点:
- 队列元素具有单调性
- 元素呈从小到大/从大到小
基本操作:
//几种操作
//1.定义
deque<数据类型> q;
//2.入队
q.push_front();//前端入队
q.push_back();//尾端入队
//3.出队
q.pop_front();//前端出队
q.pop_back();//尾端出队
//4.调用
q.front();//调用队首
q.back();//调用队尾
//5.判断队空
q.empty();//空返回1,非空返回0
//6.元素个数
q.size();
基础运用:
给定一个长为n的序列a,以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
要想做此题,一般分为三步
1.掐头:将队首不符合区间要求的元素删除
2.去尾:将当前元素加入队列,且保证加入时,队列内部依然是呈单调性
1.将队尾不符合单调性的元素删除,直到满足单调性或队列为空
2.队尾加入当前元素
3.队首为最值
1.单调递增:最小
2.单调递减:最大
//此处仅写出最小值的处理方法,最大值留给读者思考
#include <iostream>
#include <deque>
using namespace std;
const int N=2e6+5;
deque<int> q;
int n,m;
int a[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
//掐头 队首距离超过m的元素删除
while(!q.empty() && i-q.front()+1>m) q.pop_front();
//去尾 将队尾不满足单调性的删除
while(!q.empty() && a[q.back()]>=a[i]) q.pop_back();
q.push_back(i);
if(i<m) continue;
else cout<<a[q.front()]<<" ";
}
return 0;
}
我们现在再来讨论这道题:
思路
阅读题目,不难发现此题需要求和,所以要用到前缀和
再一结合可得:
#include <iostream>
#include <deque>
using namespace std;
const int N=5e5+5;
deque<int> q;
int s[N<<1],a[N<<1];
int n,m,ans=0;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=1;i<=n;i++)
{
while(!q.empty() && i-q.front()+1>m) q.pop_front();
while(!q.empty() && s[q.back()]<=s[i]) q.pop_back();
q.push_back(i);
if(i<m) continue;
int L=i-m+1,R=q.front();
int sum=s[R]-s[L-1];
ans=max(ans,sum);
}
cout<<ans;
return 0;
}
结果:60分
为什么呢?我们测一下样例2,发现过不去
输出中间值看一下:
l=1, r=3, sum=2
l=2, r=3, sum=3
l=3, r=5, sum=4
l=4, r=5, sum=1
答案是在区间[5,5]里,所以得遍历到n+m-1
一提交,尴尬了,80分
这又是为什么呢?问题出在了s[n]以后的数都是0,应该为s[n]
AC Code
#include <iostream>
#include <deque>
using namespace std;
const int N=5e5+5;
deque<int> q;
int s[N<<1],a[N<<1];
int n,m,ans=0;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(int i=n+1;i<n+m;i++) s[i]=s[i-1];
for(int i=1;i<n+m;i++)
{
while(!q.empty() && i-q.front()+1>m) q.pop_front();
while(!q.empty() && s[q.back()]<=s[i]) q.pop_back();
q.push_back(i);
if(i<m) continue;
int L=i-m+1,R=q.front();
int sum=s[R]-s[L-1];
ans=max(ans,sum);
}
cout<<ans;
return 0;
}