1 条题解
-
0
自动搬运
来自洛谷,原作者为

cyffff
Not yet for the story on the last page, it's not the end.搬运于
2025-08-24 22:44:00,当前版本为作者最后更新于2023-01-15 19:34:50,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
第一次 ,水个题解不过分吧(
题意
给一个仅包含 的序列 。在为 的位置中选 个更改为 ,其余更改为 ,使得最大子段和最大,求最大子段和的最大值。
。
思路
看数据范围像几个前缀和就做完了。
枚举左端点减一,设为 。考虑右端点 。
记原序列前缀和为 。
我们考虑定义 表示 中 的数量。我们肯定尽可能填 ,再填 ,则对 的大小分类讨论:
- ,这段的子段和为 ;
- ,这段的子段和为 。
我们定义 为第 个 的位置, 为 左方(不含 )的最后一个 是第几个 。则当 时 , 时 。
考虑将 从式子中消掉。我们定义 表示将 全部换为 后的前缀和, 表示将 全部换为 后的前缀和。则两种情况的答案分别变成了 和 。
对于后者,我们直接维护 的后缀 。对于前者,为一段区间求 ,且左右端点单调不减,维护 的单调队列即可。注意边界问题。
时间复杂度 。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long namespace IO{//by cyffff } const int N=1e7+10; int n,k,a[N],bel[N],cnt,pos[N],ans,pm[N],sm[N],p0[N],p1[N]; struct node{ int v,p; }stk[N]; int hd=1,tl; int main(){ n=read(),k=read(); for(int i=1,las=0;i<=n;i++){ a[i]=read(); bel[i]=las; if(a[i]){ p0[i]=p0[i-1]+a[i]; p1[i]=p1[i-1]+a[i]; }else{ p0[i]=p0[i-1]-1; p1[i]=p1[i-1]+1; pos[++cnt]=i,las=cnt; } } pm[n+1]=sm[n+1]=-2e9; for(int i=n;i>=1;i--) pm[i]=max(pm[i+1],p1[i]), sm[i]=max(sm[i+1],p0[i]); for(int i=0,lp=1;i<=n;i++){ while(hd<=tl&&stk[hd].p<i) hd++; int id=bel[i]+k+1; if(id>cnt) ans=max(ans,pm[i+1]-p1[i]); else{ int np=pos[id]; for(;lp<=np-1;lp++){ while(hd<=tl&&stk[tl].v<p1[lp]) tl--; stk[++tl]={p1[lp],lp}; } ans=max({ans,stk[hd].v-p1[i],sm[np]-p0[i]+2*k}); } } write(ans); flush(); }再见 qwq~
- 1
信息
- ID
- 8228
- 时间
- 777ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者