洛谷P2179 [NOI2012] 骑行川藏

题目描述

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

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

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

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

若某一时刻在这段路上骑车速度为 𝑣v,则他受到的风阻 大小为 𝐹=𝑘𝑖(𝑣−𝑣𝑖′)2F=ki​(v−vi′​)2(这样若在长度为 𝑠s 的路程内保持骑行速度 𝑣v 不变,则他消耗能量(做功)𝐸=𝑘𝑖(𝑣−𝑣𝑖′)2𝑠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% 的数据,𝑛=1n=1。

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

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

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

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

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

提示

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

Code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
double s[10005], k[10005], u[10005];
double e;
double solve(double x, int i) { 
	double l = 0, r = 100005, v;
	int batch = 60;
	while(batch--) {
		v = (l + r) / 2;
		if(2 * k[i] * s[i] * x * v * v * (v - u[i]) > -s[i]) l = v;/
		else r = v;
	}
	v = (l + r) / 2;
	return v;
}
double work(double x) {
	double sum = 0;
	for(int i = 1; i <= n; i++) {
		double v = solve(x, i);
		sum += k[i] * s[i] * (v - u[i]) * (v - u[i]);
	}
	return sum;
}
signed main() {
	cin>>n>>e;
	for(int i = 1; i <= n; i++) {
		cin>>s[i]>>k[i]>>u[i];
	}
	double l = -0x3f3f3f, r = 0, dc;
	int batch = 100;
	while(batch--) 
	{
		dc = (l + r) / 2;
		if(work(dc) <= e) l = dc;
		else r = dc;
	}
	dc = (l + r) / 2;
	double ans = 0;
	for(int i = 1; i <= n; i++)
		ans += s[i] / solve(dc, i);
	printf("%.12lf\n", ans);
	return 0;
}

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值