背景:
题目描述:
输入格式:
输出格式:
样例输入:
4 1 0 2 0 3 0 4 0
样例输出:
2.0000
数据范围:
时间限制:
1s
空间限制:
512MB
考试的时候只想到了cdq分治...没想到b的处理方法所以写了40分的结果拼上去的暴力挂了只剩下3 4的20分了
其实这题cdq分治的确可做
首先题目那个-a是忽悠你的。可以直接去掉
那么转移方程就是f[i]=min(f[i],sqrt(f[j]*f[j]+(a[i]-a[j])*(a[i]-a[j]))
我们把a[i]降序排序
然后移项后如果j>k j比k对于i优的话,那么满足((f[j]*f[j]+a[j]*a[j])+(f[k]*f[k]+a[k]*a[k]))/(2*(a[j]-a[k]))>a[i]
我们cdq分治处理左右区间。保证转移右区间的时候左区间已经转移完毕
然后左区间按照a降序,右区间按照b降序
这样就可以在枚举到右区间某个数的时候把可行左区间加入队列
然后对已经加入左区间的斜率二分就可以了
#include<cmath>
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct enemy
{
double a,b;
double f;
int p;
}x[100001],tx[100001];
int n;
double f[100001];
int q[100001];
inline bool cmp1(enemy x,enemy y)
{
return x.b>y.b;
}
inline bool cmp2(enemy x,enemy y)
{
return x.a<y.a;
}
inline double getk(int j,int k)
{
if(j==0&&k==0)
return -1;
return ((x[j].f*x[j].f+x[j].a*x[j].a)-(x[k].f*x[k].f+x[k].a*x[k].a))/(double(2)*(x[j].a-x[k].a));
}
inline void cdq(int ll,int rr)
{
if(ll!=rr)
{
int mid=(ll+rr)/2;
int i;
int p1=ll-1,p2=mid;
for(i=ll;i<=rr;i++)
{
if(x[i].p<=mid)
{
p1++;
tx[p1]=x[i];
}
else
{
p2++;
tx[p2]=x[i];
}
}
for(i=ll;i<=rr;i++)
x[i]=tx[i];
cdq(ll,mid);
sort(x+mid+1,x+rr+1,cmp1);
int r=0;
int pp=ll;
for(i=mid+1;i<=rr;i++)
{
while(x[pp].a>=x[i].b&&pp<=mid)
{
while(1<r&&getk(q[r],q[r-1])<getk(pp,q[r]))
r--;
r++;
q[r]=pp;
pp++;
}
int l0=2,r0=r;
while(l0<=r0)
{
int mid=(l0+r0)/2;
if(getk(q[mid],q[mid-1])>=x[i].a)
l0=mid+1;
else
r0=mid-1;
}
if(r0!=0)
x[i].f=min(x[i].f,sqrt(x[q[r0]].f*x[q[r0]].f+(x[q[r0]].a-x[i].a)*(x[q[r0]].a-x[i].a)));
}
cdq(mid+1,rr);
p1=ll;
p2=mid+1;
int p=ll-1;
while(p1<=mid&&p2<=rr)
{
if(x[p1].a>x[p2].a)
{
p++;
tx[p]=x[p1];
p1++;
}
else
{
p++;
tx[p]=x[p2];
p2++;
}
}
while(p1<=mid)
{
p++;
tx[p]=x[p1];
p1++;
}
while(p2<=rr)
{
p++;
tx[p]=x[p2];
p2++;
}
for(i=ll;i<=rr;i++)
x[i]=tx[i];
}
}
inline void solve2()
{
cdq(1,n);
int i;
for(i=1;i<=n;i++)
if(x[i].p==n)
break;
printf("%.4lf\n",x[i].f);
}
int main()
{
scanf("%d",&n);
int i;
bool flag=true;
for(i=1;i<=n;i++)
{
scanf("%lf%lf",&x[i].a,&x[i].b);
x[i].p=i;
if(x[i].b==0)
x[i].f=x[i].a;
else
x[i].f=1000000000;
if(x[i].b!=0)
flag=false;
}
solve2();
return 0;
}