习题:小奇探险(单调队列 & dp)
Posted loney-s
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了习题:小奇探险(单调队列 & dp)相关的知识,希望对你有一定的参考价值。
题目
小奇去遗迹探险,遗迹里有 $N$ 个宝箱,有的装满了珠宝,有的装着废品。
小奇有地图,所以它知道每一个宝箱的价值,但是它不喜欢走回头路,所以要按顺序拿这 $N$ 个宝箱中的若干个。
拿宝箱很累的。一开始小奇的体力是 $1$,每得到一个宝箱之后,小奇得到的价值是体力 $ imes$ 宝箱的价值,之后它的体力就会变为原来的 $k$ 倍 $(0<k<1)$。
小奇不喜欢连续放过很多宝箱,所以任意一段长度为 $M$ 的序列中,小奇一定要取走其中的一个宝箱。
现在小奇想知道它能得到的最大价值和。
第一行,两个整数 $N,M$,表示的含义如题目中所述;
第二行,一个小数 $k$,表示的含义如题目中所述,最多 $4$ 位小数;
第三行,$N$ 个整数,第 $i$ 个整数表示第 $i$ 个宝箱的价值。
输出一行,一个实数,表示小奇能得到的最大价值和,四舍五入保留两位小数。
思路
额。。。
考试之中的唯一一道水题
考虑从dp[i]转移到dp[i+k]
发现,转移需要考虑的要素太多,写起来太麻烦
但是如果从dp[i+k]转移到dp[i]
是不是简单了许多
$dp_i$表示前i号节点的最大值
$dp _i =max(dp_j*k+c_i,c_i) (i<j)$
看到这个转移方程,
发现k为定值,c~i~也为定值
之后又单调队列进行优化就行了
代码
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,m;
double k;
double ans;
double c[100005];
double dp[100005];
deque<int> q;
int main()
{
cin>>n>>m;
cin>>k;
for(int i=1;i<=n;i++)
cin>>c[i];
for(int i=n;i>=1;i--)
{
dp[i]=c[i];
while(!q.empty())
{
if(i+m<q.front())
q.pop_front();
else
break;
}
if(!q.empty())
dp[i]=max(dp[i],dp[q.front()]*k+c[i]);
while(!q.empty())
{
if(dp[q.back()]<dp[i])
q.pop_back();
else
break;
}
q.push_back(i);
if(i<=m)
ans=max(ans,dp[i]);
}
printf("%.2lf",ans);
return 0;
}
以上是关于习题:小奇探险(单调队列 & dp)的主要内容,如果未能解决你的问题,请参考以下文章
笔记篇单调队列优化dp学习笔记&&luogu2569_bzoj1855股票交♂易