题目链接

琪露诺

解题思路

单调队列优化的\(dp\)
状态转移方程:\(f[i]=max{f[i-l],f[i-l+1],...,f[i-r-1],f[i-r]}+a[i]\)
考虑单调队列优化。
因为刚学,不是很熟悉单调队列,特写一篇详细的解释。
\(queue\) 数组存储一个队列,他的头部和尾部的下标分别用head和tail表示。
\(f\) 数组是\(dp\)用到的数组。
首先读入每一个坐标处的价值\(a[i]\)
枚举\(i\),从\(l\)\(n\),分别计算\(f[i]\),当\(i+r>n\)时,存储最大值ans。
单调队列的注释写在代码中。

AC代码

#include<stdio.h>
int i,n,l,r,a[200010],f[200010],ans=-2147483648;//这个题数据比较水,ans=0也能过,但理论上是不允许这样的
int queue[200010],head=0,tail=-1;
int main(){
    scanf("%d%d%d",&n,&l,&r);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(i=l;i<=n;i++){
        while(head<=tail&&queue[head]+r<=i)head++;//如果头太靠前了,那就删掉
        while(head<=tail&&f[queue[tail]]<=f[i-l])tail--;//如果尾巴对应的a太小了,那就删掉
         //这两句保证了单调队列的不上升也即单调减特性,保证头永远是当前状态的最佳状态
        queue[++tail]=i-l;//存储上一次是从哪里来的
        f[i]=a[i]+f[queue[head]];//从上一步跳过来,跳到这里的最大值
        if(i>n-r&&f[i]>ans)ans=f[i];
    }
    printf("%d",ans);
    return 0;
}