题目链接:Click here~~
题意:
一个人带着初始的 X 元钱和 Y 的攻击力,依次经过 n 个城市从 1~n。在每个城市可以做两件事,花钱提升攻击力和用攻击力赚钱,且顺序不能改变。
问最后从 n 出来时最多能有多少钱。(提升攻击力单价为 1点 / a[i] 元,但可以提升非整点的攻击力;攻击力赚钱情况为 b[i] 元 / 点)
解题思路:
由于攻击力和钱数都可能是实数,所以不能以它两个作为状态了。
问题中赚钱只有一个途径——打工。而打工没有什么限制,即有多少攻击力,就能赚多少相应的钱。不会因为当前的钱多或攻击力多,而获得额外的钱。
同样地,提升攻击力也不会因为钱多或攻击力多,而获得额外的攻击力。
这点对问题有什么帮助呢?
1、在某个城市 i,1点攻击力能获得的最大钱数 和 1块钱能获得的最大钱数 与 当前拥有的钱数和攻击力 是无关的。
2、钱和攻击力能获得的最大钱数可以分开考虑。
令 att_m[i] 表示带着 1点攻击力 进入城市 i 能获得的最大钱数,mon_m[i] 表示带着 1块钱 进入城市 i 能获得的最大钱数。
初始值:att_m[n] = b[n] , mon_m[n] = max(1,1.0/a[n] * b[n])。
转移方程: att_m[i] = mon_m[i+1] * b[i] + att_m[i+1] ,mon_m[i] = max(mon_m[i+1],1.0/a[i] * (b[i] * mon_m[i+1] + att_m[i+1]))。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 1e5 + 5; double a[N],b[N],mon_m[N],att_m[N]; int main() { int n,X,Y; while(~scanf("%d%d%d",&n,&X,&Y)) { for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i],&b[i]); att_m[n] = b[n]; mon_m[n] = max(1.0,1.0/a[n] * b[n]); for(int i=n-1;i>=1;i--) { att_m[i] = mon_m[i+1] * b[i] + att_m[i+1]; mon_m[i] = max(mon_m[i+1],1.0/a[i] * (b[i] * mon_m[i+1] + att_m[i+1])); } printf("%.2f\n",X*mon_m[1] + Y*att_m[1]); } return 0; }