习题:小奇探险(单调队列 & dp)

前提是你 提交于 2019-12-02 03:33:01

题目

小奇去遗迹探险,遗迹里有 $N$ 个宝箱,有的装满了珠宝,有的装着废品。

小奇有地图,所以它知道每一个宝箱的价值,但是它不喜欢走回头路,所以要按顺序拿这 $N$ 个宝箱中的若干个。

拿宝箱很累的。一开始小奇的体力是 $1$,每得到一个宝箱之后,小奇得到的价值是体力 $\times$ 宝箱的价值,之后它的体力就会变为原来的 $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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!