码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-10-23 22:06:12      阅读:89      评论:0      收藏:0      [点我收藏+]

标签:name   水题   价值   empty   max   for   while   int   ios   

题目

小奇去遗迹探险,遗迹里有 $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;
}

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

标签:name   水题   价值   empty   max   for   while   int   ios   

原文地址:https://www.cnblogs.com/loney-s/p/11729105.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!