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