P2179 [NOI2012] 骑行川藏

                                                      前言

我姐姐买狗时被骗1200元,还签了支付宝合同,每月自动扣款300元,缴12个月。家人不报警,在评论区求解决,谢谢!

题目描述

蛋蛋非常热衷于挑战自我,今年暑假他准备沿川藏线骑着自行车从成都前往拉萨。

川藏线的沿途有着非常美丽的风景,但在这一路上也有着很多的艰难险阻,路况变化多端,而蛋蛋的体力十分有限,因此在每天的骑行前设定好目的地,同时合理分配好自己的体力是一件非常重要的事情。

由于蛋蛋装备了一辆非常好的自行车,因此在骑行过程中可以认为他仅在克服风阻做功(不受自行车本身摩擦力以及自行车与地面的摩擦力影响)。

某一天他打算骑 n 段路,每一段内的路况可视为相同:对于第 i 段路,我们给出有关这段路况的 33 个参数 ′si​,ki​,vi′​,其中 si​ 表示这段路的长度,ki​ 表示这段路的风阻系数,′vi′​ 表示这段路上的风速(′vi′​>0 表示在这段路上他遇到了顺风,反之则意味着他将受逆风影响)。

若某一时刻在这段路上骑车速度为 v,则他受到的风阻 大小为 2F=ki​(v−vi′​)2(这样若在长度为 s 的路程内保持骑行速度 v 不变,则他消耗能量(做功)E=ki​(v−vi′​)2s )。

设蛋蛋在这天开始时的体能值是 EU​,请帮助他设计一种行车方案,使他在有限的体力内用最短的时间到达目的地。请告诉他最短的时间 T 是多少。

输入格式

第一行包含一个正整数 n 和一个实数 EU​,分别表示路段的数量以及蛋蛋的体能值。

接下来 n 行分别描述 n 个路段,每行有 33 个实数 ′si​,ki​,vi′​ 分别表示第 �i 段路的长度,风阻系数以及风速。

输出格式

输出一个实数 T,表示蛋蛋到达目的地消耗的最短时间,要求至少保留到小数点后 66 位。

输入输出样例

输入 #1复制

3 10000
10000 10 5
20000 15 8
50000 5 6

输出 #1复制

12531.34496464

说明/提示

样例说明

一种可能的方案是:蛋蛋在三段路上都采用匀速骑行的方式,其速度依次为 5.12939919,8.03515481,6.178379675.12939919,8.03515481,6.17837967。

评分方法

本题没有部分分,你程序的输出只有和标准答案的差距不超过 10−610−6 时,才能获得该测试点的满分,否则不得分。

数据规模与约定

对于 10%10% 的数据,n=1。

对于 40%40% 的数据,n≤2。

对于 60%60% 的数据,n≤100。

对于 80%80% 的数据,n≤1000。

对于 100%100% 的数据,n≤104,EU​≤108,si​∈[0,105],ki​∈(0,15],vi′​∈(−100,100)。

数据保证最终的答案不会超过 105105。

提示

必然存在一种最优的体力方案满足:蛋蛋在每段路上都采用匀速骑行的方式。

题解

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define enter putchar('\n')
#define space putchar(' ')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op == 1) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 10005, INF = 0x3f3f3f3f;
int n;
double E, s[N], k[N], u[N];

double getv(double x, int i){
    double l = max(u[i], double(0)), r = 100005, mid;
    int cnt = 60;
    while(cnt--){
        mid = (l + r) / 2;
        if(2 * k[i] * x * mid * mid * (mid - u[i]) > -s[i]) l = mid;
        else r = mid;
    }
    mid = (l + r) / 2;
    return (l + r) / 2;
}
double calc(double x){
    double sum = 0;
    for(int i = 1; i <= n; i++){
        double v = getv(x, i);
        sum += k[i] * (v - u[i]) * (v - u[i]);
    }
    return sum;
}

int main(){
    scanf("%d%lf", &n, &E);
    for(int i = 1; i <= n; i++)
        scanf("%lf%lf%lf", &s[i], &k[i], &u[i]), k[i] *= s[i];
    double l = -INF, r = 0, mid;
    int cnt = 100;
    while(cnt--){
        mid = (l + r) / 2;
        if(calc(mid) <= E) l = mid;
        else r = mid;
    }
    mid = (l + r) / 2;
    double ans = 0;
    for(int i = 1; i <= n; i++)
        ans += s[i] / getv(mid, i);
    printf("%.10lf\n", ans);
    return 0;
}

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值