式子:
e
a
r
n
[
i
]
=
a
−
c
[
i
]
earn[i]=a-c[i]
earn[i]=a−c[i]
s
u
m
[
i
]
=
∑
j
=
1
i
e
a
r
n
[
j
]
,
(
1
≤
i
≤
n
)
sum[i]=\sum_{j=1}^{i}earn[j],(1≤i≤n)
sum[i]=j=1∑iearn[j],(1≤i≤n)
a
n
s
=
m
a
x
{
s
u
m
[
r
]
−
s
u
m
[
l
−
1
]
+
g
a
p
(
l
,
r
)
}
ans=max\{sum[r]-sum[l-1]+gap(l,r)\}
ans=max{sum[r]−sum[l−1]+gap(l,r)}
纯单调栈:
O
(
n
)
O(n)
O(n) 从后往前枚举左端点:
a
n
s
=
m
a
x
{
s
u
m
[
r
]
+
g
a
p
(
l
,
r
)
−
s
u
m
[
l
−
1
]
}
ans=max\{sum[r]+gap(l,r)-sum[l-1]\}
ans=max{sum[r]+gap(l,r)−sum[l−1]}左端点固定时,式子中的最后一项
s
u
m
[
l
−
1
]
sum[l-1]
sum[l−1]是一定的,每当左端点向左移动一位时,
g
(
l
,
r
)
g(l,r)
g(l,r)可能会改变。 假定左端点向左移动一位时新增的差值为
s
d
,
s
d
=
d
[
l
+
1
]
−
d
[
l
]
sd,sd=d[l+1]-d[l]
sd,sd=d[l+1]−d[l],考虑以
s
d
sd
sd为
g
(
l
,
r
)
g(l,r)
g(l,r)的右端点
r
r
r,且在这些右端点中记录最大的
m
a
x
[
r
]
max[r]
max[r],记为
v
a
l
val
val,那么
v
a
l
−
s
d
∗
s
d
−
e
a
r
n
[
l
]
val-sd*sd-earn[l]
val−sd∗sd−earn[l]就可能成为最大值,记为A。同时也要记录
[
l
+
1
,
r
]
[l+1,r]
[l+1,r]内最大合法的的
s
u
m
[
r
]
+
g
a
p
(
l
+
1
,
r
)
sum[r]+gap(l+1,r)
sum[r]+gap(l+1,r),记为B,并取
m
a
x
(
A
,
B
)
−
e
a
r
n
[
l
−
1
]
max(A,B)-earn[l-1]
max(A,B)−earn[l−1]更新答案。 因为是新值先处理的思路,所以用栈来做。注意
l
=
r
l=r
l=r的情况,状态要从合法的情况转移过来。
单调栈+线段树最大子段和:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 观察式子
a
n
s
=
m
a
x
{
s
u
m
[
r
]
−
s
u
m
[
l
−
1
]
+
g
a
p
(
l
,
r
)
}
ans=max\{sum[r]-sum[l-1]+gap(l,r)\}
ans=max{sum[r]−sum[l−1]+gap(l,r)},如果没有最后一项,前面可以通过线段树求
[
1
,
n
]
[1,n]
[1,n]的最大子段和得到。有最后一项的话,枚举差值
s
d
sd
sd,通过单调栈预处理出以当前位置的
s
d
sd
sd为
g
a
p
(
l
,
r
)
gap(l,r)
gap(l,r)的区间
l
,
r
l,r
l,r,在
l
,
r
l,r
l,r区间内查询最大子段和,不断更新答案,特殊处理下选择
l
=
r
l=r
l=r这种情况。 大佬详解
ac代码: 纯单调栈做法:
#include<bits/stdc++.h>
using namespace std;typedeflonglong ll;constint maxn =3e5+10;int n;
ll a, c;
ll d[maxn], earn[maxn];struct node{
ll sub, val, mx_all;}s[maxn];intmain(){//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);scanf("%d %lld",&n,&a);for(int i =1; i <= n; i++)scanf("%lld %lld",&d[i],&c), earn[i]= earn[i-1]+(a-c);int top =0;
ll ans =max(0ll, a-c);
s[++top]={0, earn[n], earn[n]};
s[0].mx_all = LLONG_MIN;for(int i = n-1; i >=1; i--){
ll sd = d[i+1]-d[i], mx = LLONG_MIN;while(top>0&& s[top].sub<=sd) mx =max(mx, s[top--].val);
top++; s[top]={sd, mx,max(s[top-1].mx_all, mx-sd*sd)};
top++; s[top]={0, earn[i],max(s[top-1].mx_all, earn[i])};
ans =max(ans, s[top].mx_all-earn[i-1]);}printf("%lld\n", ans);return0;}