纯DP,公式如下
#include<iostream>
using namespace std;
const int N = 2e5 + 10;
int n,l,r;
int st[N];
int f[N];
int p[N];
int main() {
scanf("%d%d%d",&n,&l,&r);
for(int i = 0; i <= n; i++) scanf("%d",&st[i]);
p[0] = 1;
for(int i = 0; i <= n; i++) {
if(i-l >= 0) {
for(int j = max(0,i-r); j <= max(0,i-l); j++) {
if(p[j]) {
f[i] = max(f[i],st[i] + f[j]);
p[i] = 1;
}
}
}
}
int ans = 0;
for(int i = n - r;i <= n;i++)
if(p[i])
ans = max(ans,f[i]);
printf("%d",ans);
return 0;
}
树状数组 进行优化
对于 i - r ~ i - l 区间我们可以用树状数组快速求最大值,减少复杂度
建立过程:对f数组赋初值(-0x7f),对于能够从第0个格子到达的点i来说,它的f[i]必将被改变。不被改变的f[i],必然是无法到达的。每次更新f[i]时,将其加入到树状数组中进行维护,又因为是从左到右更新,因此在树状数组必然可以找到上一个点能够跳转到该点的最大值。求解成功后,答案就是[n+1-r,n]的最大值
#include<iostream>
#include<cstring>
using namespace std;
const int N = 2e5 + 10;
int n,l,r;
int st[N];
int f[N];
int p[N];
int treex[N];
int lowbit(int x) {
return x & -x;
}
void _add(int x,int k) {
for(; x <= n; x += lowbit(x)) {
treex[x] = max(treex[x],k);
}
}
int findMax(int x,int y) {
if(y > x) {
if(y - lowbit(y) > x) return max(treex[y],findMax(x,y-lowbit(y)));
else return max(f[y],findMax(x,y-1));
}
return f[y];
}
int main() {
scanf("%d%d%d",&n,&l,&r);
for(int i = 0; i <= n; i++) scanf("%d",&st[i]);
memset(f,-0x7f,sizeof f);
f[0] = 0;
p[0] = 1;
for(int i = 0; i <= n; i++) {
if(i-l >= 0) {
int a = max(0,i - r), b = max(0,i-l);
int val = findMax(a,b);
f[i] = max(f[i], st[i] + val);
if(i > 0) _add(i,f[i]);
}
}
int ans = -0x7f;
for(int i = n+1 - r; i <= n; i++)
ans = max(ans,f[i]);
printf("%d",ans);
return 0;
}