NOIP模拟赛-小奇挖矿
NOIP模拟赛:小奇挖矿
hzwer大佬果然是甜甜私房猫爱好者...
题目背景
小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值 w)的飞船,按既定
路线依次飞过喵星系的 n 个星球。
问题描述
星球分为 2 类:资源型和维修型。
资源型:含矿物质量 a[i],若选择开采,则得到 a[i]p 的金钱,之后钻头
损耗 k%,即 p=p(1-0.01k)
维修型:维护费用 b[i],若选择维修,则支付 b[i]p 的金钱,之后钻头修
复 c%,即 p=p(1+0.01c)(p 为钻头当前能力值)
注:维修后钻头的能力值可以超过初始值
请你帮它决策最大化这个收入。
数据范围
对于 30%的数据 n<=100
对于 50%的数据 n<=1000,k=100
对于 100%的数据 n<=100000,0<=k,c,w,a[i],b[i]<=100
保证答案不超过
题解
很容易就能想到一个三维DP:设表示考虑前i个元素,选取j个资源型,k个维修型的最大价值。
由于每个维修点和资源点对钻头耐久的影响是相同的,所以只需要统计个数就能很方便的计算下一个点的贡献。
但是这样做的时间复杂度是显然会超时,考虑优化。
为什么我们必须要枚举三维dp呢?是因为前面的决策会对后续点的贡献造成影响。
这个影响的大小可以很方便地利用乘法分配律进行维护,但很可惜我们并不知道后面的最大价值...
[异议?!]从后往前dp不就可以知道后面的价值了吗?
由于每一次转移都不需要关心之前的决策,只需要维护价值;所以每一个决策都是相互独立的;
这样我们就可以回归纯粹的一维线性状态dp,用一个近乎贪心的做法完美地解决本题。
设f[i]为后i个点的最大价值,得到转移方程:
代码时间
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int n,k,c,w;
struct node{
double a,b;
}d[100005];
double f[100005];
int main(){
freopen("explo.in","r",stdin);
freopen("explo.out","w",stdout);
n=read(),k=read(),c=read(),w=read();
for(int i=1;i<=n;i++){
d[i].b=read();
d[i].a=read();
}
for(int i=n;i>=1;i--){
if(d[i].b==1)f[i]=max(f[i+1],f[i+1]*(1-0.01*k)+d[i].a);
else f[i]=max(f[i+1],f[i+1]*(1+0.01*c)-d[i].a);
}
f[1]=f[1]*w;
printf("%.2lf",f[1]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本