LuoguP1714 切蛋糕
不定长子段和~ 采用前缀和加单调队列来维护。
-
我们通过 \(S_r - S_{l-1}\) 来表示子段 \([l,r]\) 的和。其中, \(S_i=S_{i-1}+P_i\)(前缀和)。
-
求出:
\[\max \limits_{i\in [1,N]}\Big\{S_i-\min \limits_{j\in [i-M,i)}\{S_j\}\Big\}
\]
- 其中,\(\min \limits_{j\in [i-m,i)}\{S_j\}\) 可以采用 单调队列 维护。
代码(复杂度 \(O(N)\)):
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<utility>
using namespace std;
int n,m,p,s,ans=-2147483647;
class monotonic_queue{
int head,tail;
bool ml;//true more, false less
pair<int,int> node[500005];//提交时请增加至 N(电脑不分配内存QAQ)
bool cmp(int x,int y){
if(ml)return x<y;
else return x>y;
}
public:
monotonic_queue(bool ml):ml(ml){head=1;tail=0;};
void pushback(int position,int data){
while(head<=tail&&(!cmp(node[tail].second,data)))tail--;
node[++tail]=make_pair(position,data);
}
void popfront(int position){
if(node[head].first<=position)head++;
}
int top(){return node[head].second;}
};
signed main(){
scanf("%d%d",&n,&m);
monotonic_queue inc(true);
inc.pushback(0,0);
for(int i=1;i<=n;i++){
scanf("%d",&p);
s+=p;
ans=max(ans,s-inc.top());
inc.pushback(i,s),inc.popfront(i-m);
}printf("%d",ans);
return 0;
}