标签:DP状态机
这天,一只蜗牛来到了二维坐标系的原点。
在 x 轴上长有 n 根竹竿。
它们平行于 y 轴,底部纵坐标为 00,横坐标分别为 x1,x2,…,xn。
竹竿的高度均为无限高,宽度可忽略。
蜗牛想要从原点走到第 n 个竹竿的底部也就是坐标 (xn,0)。
它只能在 x 轴上或者竹竿上爬行,在 x 轴上爬行速度为 11 单位每秒;由于受到引力影响,蜗牛在竹竿上向上和向下爬行的速度分别为 0.70.7 单位每秒和 1.31.3 单位每秒。
为了快速到达目的地,它施展了魔法,在第 i 和 i+1 根竹竿之间建立了传送门(0<i<n),如果蜗牛位于第 i 根竹竿的高度为 ai 的位置 (xi,ai),就可以瞬间到达第 i+1 根竹竿的高度为 bi+1 的位置 (xi+1,bi+1),请计算蜗牛最少需要多少秒才能到达目的地。
输入格式
输入共 1+n行,第一行为一个正整数 n;
第二行为 n个正整数 x1,x2,…,xn;
后面 n−1行,每行两个正整数 ai,bi+1。
输出格式
输出共一行,一个浮点数表示答案(四舍五入保留两位小数)。
数据范围
对于 20% 的数据,保证 n≤15;
对于 100% 的数据,保证 1≤n≤105,1≤ai,bi≤104,1≤xi≤109。
输入样例:
3
1 10 11
1 1
2 1
输出样例:
4.20
样例解释
蜗牛路线:
(0,0)→(1,0)→(1,1)→(10,1)→(10,0)→(11,0),花费时间为 1+1/0.7+0+1/1.3+1≈4.20
/* dp状态机问题 */
/* 两维问题,两个状态,使用或不使用传送门 */
/* 直接从竹竿底部走和经过当前的传送门传送到下一个竹竿的某个位置,可以将两种思想用0和1表示 */
/* 注意:走转送门要确定转送门在上面还是下面,故这里运用Teleport[i - 1].b >= Teleport[i].a ? 1.3 : 0.7确定 */
/* 如果三目运算符不熟练也可以用if判断 */
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/* 根据题目定义,方便理解 */
#define a first
#define b second
const int N = 1e5 + 10; // 开大范围,防止超范围
typedef long long LL;
typedef pair<int, int> PII;
PII Teleport[N]; // 确定传送方位
double f[N][2]; // 根据题意有小数,用double
int x[N];
int n;
int main()
{
/* 正常读入 */
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> x[i];
for (int i = 1; i < n; i ++ ) cin >> Teleport[i].a >> Teleport[i].b;
memset(f, 0x3f, sizeof f); //求最小值,初始化正无穷
/* 0为不使用传送门,1为使用传送门 */
f[1][0] = x[1]; f[1][1] = Teleport[1].a / 0.7 + x[1]; //初始化两种情况,使用和不使用传送门
for (int i = 2; i <= n; i ++ ) // 1已经初始化,从2开始
{
f[i][0] = f[i - 1][0] + x[i] - x[i - 1]; // 不使用传送门
f[i][0] = min(f[i][0], f[i - 1][1] + Teleport[i - 1].b / 1.3); // 上一步使用传送门与不使用对比取最小值
f[i][1] = f[i][0] + Teleport[i].a / 0.7; // 使用传送门
f[i][1] = min(f[i][1], f[i - 1][1] + abs(Teleport[i - 1].b - Teleport[i].a) / (Teleport[i - 1].b >= Teleport[i].a ? 1.3 : 0.7)); // 同理取最小值
}
printf("%.2lf" , f[n][0]); // 输出记得保两位小数(^-^)
return 0;
}