我们设
f
i
f_i
fi 表示 i 结尾的最大子段和,那么:
f
i
=
M
a
x
(
s
u
m
i
−
s
u
m
j
)
,
(
1
<
=
i
−
j
<
=
m
)
f_i=Max(sum_i-sum_j),(1<=i-j<=m)
fi=Max(sumi−sumj),(1<=i−j<=m)
观察当我们在枚举第 i 个位置的时候:
s
u
m
i
sum_i
sumi 是变量,所有我们将
s
u
m
i
sum_i
sumi 从上面的式子提出来,那么原式变成:
f
i
=
s
u
m
i
−
M
i
n
(
s
u
m
j
)
,
(
1
<
=
i
−
j
<
=
m
)
f_i=sum_i-Min(sum_j),(1<=i-j<=m)
fi=sumi−Min(sumj),(1<=i−j<=m),
而
M
i
n
(
s
u
m
j
)
Min(sum_j)
Min(sumj) 是可以用单调队列的优化的。
代码
#include<bits/stdc++.h>
using namespace std;#definedbdouble#definelllonglong#definePirpair<int,int>#definefifirst#definesesecond#definepbpush_back#definem_pmake_pair#defineinf0x3f3f3f3f#defineINF0x3f3f3f3f3f3f3f3f/*==========ACMer===========*/constint N =300005;int n, m;int a[N], tt, hh;
ll sm[N], q[N];intmain(){scanf("%d %d",&n,&m);for(int i =1; i <= n; i ++){scanf("%d",&a[i]);
sm[i]= sm[i -1]+ a[i];}
ll ans =-INF;
hh =0, tt =-1;
q[++ tt]=0;for(int i =1; i <= n; i ++){if(tt >= hh && i - q[hh]> m) hh ++;while(tt >= hh && sm[q[tt]]>= sm[i]) tt --;
ans =max(ans, sm[i]- sm[q[hh]]);
q[++ tt]= i;}printf("%lld\n", ans);return0;}