您的位置:首页 > 其它

bzoj2765: [JLOI2010]铁人双项比赛

2017-05-10 08:12 190 查看

题解

  这题思路好像不是那么明显。

  你可以列出每个人的用时关于k的式子

  ti=(1v1−1v2)k+sv2

  那么你就要选择一个恰当的k使得tn最小且次小值与它的差最大。

  那就是说有若干条直线,你要找一个横坐标使得第n条直线在最下方,且次小的直线与它的差值最小。

  显然这样的横坐标肯定是某个交点的横坐标。因此我们可以求出所有的交点,然后每个交点检验一下它是不是在最下方的交点,然后再更新下答案就好了。

  这样是O(n3)

代码

//计算几何
#include <cstdio>
#include <algorithm>
#include <cmath>
#define maxn 233
#define eps 1e-8
using namespace std;
int N, tot;
double k[maxn], b[maxn], dy=-1e100, s, dx;
struct point{double x, y;}pt[maxn*maxn];
point jiao(int l1, int l2)
{
point pt;
if(fabs(k[l1]-k[l2])<eps)return (point){-1,-1};
pt.x=(b[l1]-b[l2])/(k[l2]-k[l1]);
pt.y=pt.x*k[l1]+b[l1];
return pt;
}
void input()
{
int i;
double v1, v2;
scanf("%lf%d",&s,&N);
for(i=1;i<=N;i++)
{
scanf("%lf%lf",&v1,&v2);
k[i]=1/v1-1/v2;
b[i]=s/v2;
}
}
void solve()
{
int i, j;
double t, x, y;
for(i=1;i<=tot;i++)
{
x=pt[i].x, y=pt[i].y;
if(x<0 or x>s)continue;
for(j=1;j<N;j++)if(k[j]*x+b[j]<y-eps)break;
if(j==N)
if(y-k
*x-b
>dy)dy=y-k
*x-b
, dx=x;
}
}
int main()
{
int i, j;
input();
for(i=1;i<N;i++)for(j=i+1;j<N;j++)pt[++tot]=jiao(i,j);
for(i=1;i<=N;i++)pt[++tot]=(point){0,b[i]}, pt[++tot]=(point){s,k[i]*s+b[i]};
solve();
if(dy<-eps)printf("NO");
else printf("%.2lf %.2lf %d",dx,s-dx,(int)(dy*3600+0.5));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: