/*可以用单调队列优化的DP一般是用于限定长度的区间,且区间有整体移动的趋势。即每一个元素是逐次进出区间,且只有一次。这样的题目一般都是有比较明显的模板。下面的这个就是集训的时候学长给的模板。感觉挺好写和理解。不过综合对比时间效率。感觉不一定是最高效的。
题意是给你固定的区间长度范围。求该序列首端和末端的和最大值。
简单。维护一个单调队列进行优化即可。有些细节看代码的注释。*/
#include <iostream>
#include <stdio.h>
#include <cstring>
#define maxn 100010
//#define inf -1000000000
#define inf 0x7fffffff
using namespace std;
struct node
{
int num,id;
node() {}
node(int _num,int _id)
{
num=_num;
id=_id;
}
} q[maxn];
int dp[maxn];
int a[maxn];
int main()
{
int n,m,len;
while(scanf("%d",&len)==1)
{
dp[0]=0;
scanf("%d%d",&n,&m);
for(int i=1; i<=len; i++)
if(i<=n-1) dp[i]=inf;//1到n-1没有意义
int head=0,rear=0;
q[rear++]=node(0,1);
for(int i=1; i<=len; i++)
{
scanf("%d",&a[i]);
if(i>=n)
{
while(head<rear&&q[rear-1].num<=dp[i-n]+a[i-n+1]) rear--;//将i-n加入,i-m已经在队列中.
q[rear++]=node(dp[i-n]+a[i-n+1],i-n);
while(head<rear&&i-q[head].id>m) head++;//注意是>m..知道找到<=m时跳出.<=m是我们需要的情况
dp[i]=q[head].num+a[i];
}
}
printf("%d\n",dp[len]);
}
return 0;
}
Sequences hoj 单调队列优化DP
最新推荐文章于 2022-08-04 13:24:44 发布