UVA1753 Need for Speed
2019-10-28

OIer写代码,总会遇到几个玄学错误。

题意描述

Winniechen有一辆车, 但是它的迈速表指针坏掉的。当度数为ss的时候, 车的实际速度是 s+cs+ccc是一个不确定的实数(常数。现在给你一段行程,包含n个路段, 保证每个路段是均速行驶的, 每个描述有两个数字, 分别为行驶的路程did_i和迈速表的读数sis_i。整个行程一共用了tt的时间, 请确定cc的值。另外请注意, 他的真实速度是永远保持在0以上的。

原题链接

Solve

首先,我们蒙一个cc做答案。

然后试一试,如果用时超过tt的话,就是速度太慢了,应该给他提提速。如果小于mm的话,就是速度太快了,应该给他降一降,如果用时等于tt的话,bingo,恭喜你猜对了。
所以,我们惊奇的发现,这个cc具有“单调性”,这意味着什么?我们可以有规律地去猜。
二分答案。而判断就是用用时与tt的关系。
特殊之处就在于,是实数域上的二分。
无非就是把

while(l<=r){
	mid=(l+r)>>1;
	if(···) l=mid+1;
	else r=mid-1; 
} 

换成

while(l<=r-eps){
	mid=(l+r)/2;
	if(···) l=mid;
	else r=mid; 
} 

所有变量都是double类型。eps就是你想要卡的精度。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100000
#define db double
using namespace std;
int n;
db s[N],d[N];
db t,sum;
db l,r,mid,eps=1e-9;//就是这个
bool solve(db c){
	sum=0;
	for(int i=1;i<=n;i++){
		if(s[i]+c<=0) return true;//如果速度小于0的话就跟就GG了
		sum+=(d[i]/(s[i]+c)); 
	}
	if(sum>t) return true;
	else return false;
}
int main()
{
	while(scanf("%d%lf",&n,&t)!=EOF){//记住这个“!=EOF”
		l=-20000000,r=20000000;
		for(int i=1;i<=n;i++) scanf("%lf%lf",&d[i],&s[i]);
		for(int i=1;i<=100;i++){
			mid=(l+r)/2;
			if(solve(mid)) l=mid;
			else r=mid;
		}
		printf("%.9lf\n",l);
	}
}

后言

我原以为加不加EOF都一样的,或者是“~”取反,但是某谷给了我一个大大的耳光,我T飞了。
所以观察答案有“单调性”的话,二分莽就完了。