题目描述:
Solution
我们如果选了一段区间,那么这段区间一定需要包含至少 k k k个数。
我们设
f
[
i
]
f[i]
f[i]表示选到底i个数的最大权值。
设
m
a
x
x
[
i
]
=
m
a
x
j
=
1
i
(
f
[
j
]
)
maxx[i]=max_{j=1}^{i}(f[j])
maxx[i]=maxj=1i(f[j])
然后再有一个前缀和数组
s
u
m
su m
sum
如果不选第
i
i
i个数:
f
[
i
]
=
f
[
i
−
1
]
;
f[i]=f[i-1];
f[i]=f[i−1];
如果选第i个数,很容易得到以下的dp式子:
f
[
i
]
=
m
a
x
(
m
a
x
x
[
j
]
+
s
u
m
[
i
]
−
s
u
m
[
j
]
)
(
i
−
j
>
=
k
)
f[i]=max(maxx[j]+sum[i]-sum[j]) (i-j>=k)
f[i]=max(maxx[j]+sum[i]−sum[j])(i−j>=k)
我们把
s
u
m
sum
sum提出,就有了以下式子:
f
[
i
]
=
m
a
x
(
m
a
x
x
[
j
]
−
s
u
m
[
j
]
)
+
s
u
m
[
i
]
(
i
−
j
>
=
k
)
f[i]=max(maxx[j]-sum[j])+sum[i] (i-j>=k)
f[i]=max(maxx[j]−sum[j])+sum[i](i−j>=k)
于是,我们只要维护一个关于 m a x x [ j ] − s u m [ j ] maxx[j]-sum[j] maxx[j]−sum[j]的前缀最大值即可。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 6e6+10;
int n,a[N],sum[N],k;
int f[N];
signed main(){
freopen("union.in","r",stdin);
freopen("union.out","w",stdout);
scanf("%lld %lld",&n,&k);
for (int i = 1; i <= n; i++) scanf("%lld",&a[i]),sum[i] = sum[i-1] + a[i];
int Maxx = 0;
for (int i = k; i <= n; i++){
Maxx = max(Maxx,f[i-k]-sum[i-k]);//前缀最大值
f[i] = max(f[i-1],Maxx+sum[i]);//直接通过铅坠最大值转移
}
Maxx = 0;
for (int i = 1; i <= n; i++) Maxx = max(Maxx,f[i]);
cout<<Maxx;
return 0;
}