Description
众所周知,在P国外不远处盘踞着巨龙大Y。
传说中,在远古时代,巨龙大Y将P国的镇国之宝窃走并藏在了其巢穴中,这吸引着整个P国的所有冒险家前去夺回,尤其是皇家卫士队的队长小W。
在P国量子科技实验室的帮助下,队长小W通过量子传输进入了巨龙大Y的藏宝室,并成功夺回了镇国之宝。
但此时巨龙布下的攻击性防壁启动,将小W困在了美杜莎的迷宫当中。
被困在迷宫(0,0)处的队长小W快速观察了美杜莎的迷宫的构造,发现迷宫的出口位于(p,q)处。
巨龙大Y在迷宫当中布置了n火焰吐息机关,每个机关可以用三个参数(x,y,θ)表示,分别指明机关位于平面的坐标(x,y),以及火焰吐息的方向相对于x正方向的倾角θ。
巨龙强大的力量使得火焰吐息有无穷长,且队长小W不能通过被火焰吐息覆盖的射线(注意,机关所处的坐标若没有被其他火焰吐息覆盖,则是可以通过的)。
同时,迷宫在沿x负方向无穷远的地方放置了美杜莎之眼,使得队长小W必须倾向于向x正方向行动(即队长小W的移动方向在x正方向上的投影必须为正,不能是负数或零),否则队长小W将被瞬间石化而无法逃离。
心急如焚的队长小W需要趁着巨龙大Y还没将其抓住前逃离美杜莎的迷宫,所以他立马向P国智囊团求助,作为智囊团团长的你,一定可以帮队长小W找出安全逃至迷宫出口的最短道路。
Input
第一行为三个整数n,p,q,分别表示火焰吐息机关总数以及出口坐标。
接下来n行,每行两个整数与一个实数(x,y,θ)分别表示机关所处的坐标以及火焰吐息的关于x正方向的倾角。
Output
输出文件仅包含一行一个小数,表示最短道路的长度。
当你的答案和标准答案的相对误差不超过10^-8时(即|a-o|/a≤10-8时,其中a是标准答案,o是输出)认为你的答案正确。
Sample Input
7 20 -5
4 3 -2.875
5 7 -1.314
10 -2 0.666
16 1 -1.571
16 1 1.571
23 -3 -2.130
14 -5 3.073
4 3 -2.875
5 7 -1.314
10 -2 0.666
16 1 -1.571
16 1 1.571
23 -3 -2.130
14 -5 3.073
Sample Output
33.3380422500
题解Here!
其实吧,我也不知道正解是什么,但是看正解感觉像个单调队列。。。
有时间再来填这个坑吧。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #define MAXN 1000010 using namespace std; const double PI=acos(-1); int n,top=0,head[2],tail[2]; struct Point{ long long x,y; Point *next; int direction; Point operator +(const Point &p)const{return (Point){x+p.x,y+p.y};} Point operator -(const Point &p)const{return (Point){x-p.x,y-p.y};} long long operator *(const Point &p)const{return x*p.y-y*p.x;} bool operator !=(const Point &p)const{return (x!=p.x||y!=p.y);} bool operator <(const Point &p)const{return x<p.x;} double dis()const{return sqrt(x*x+y*y);} }s,t,a[MAXN],b[MAXN],*que[2][MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline bool NotInRange(double div,double x,double y){ if(div>=-PI/2.0&&div<=PI/2.0)return ((x<div||x>PI/2.0)&&(y<div||y>PI/2.0)); else if(div<0)return (x>div&&x<PI/2.0&&y>div&&y<PI/2.0); else return ((x>div||x<PI/2.0)&&(y>div||y<PI/2.0)); } void work(){ double ans=0; head[0]=tail[0]=head[1]=tail[1]=1; que[0][1]=que[1][1]=&s; for(int i=1;i<=n;i++){ int x=a[i].direction,y=x^1; if(head[y]<tail[y]&&((a[i]-*que[y][head[y]])*(*que[y][head[y]+1]-*que[y][head[y]]))*(x==1?1:-1)>=0){ while(head[y]<tail[y]&&((a[i]-*que[y][head[y]])*(*que[y][head[y]+1]-*que[y][head[y]]))*(x==1?1:-1)>=0)head[y]++; a[i].next=que[y][head[y]]; head[x]=tail[x]=tail[x]+1; que[x][head[x]]=que[y][head[y]]; }else{ while(head[x]<tail[x]&&((a[i]-*que[x][tail[x]-1])*(*que[x][tail[x]]-*que[x][tail[x]-1]))*(x==1?1:-1)>=0)tail[x]--; a[i].next=que[x][tail[x]]; } que[x][++tail[x]]=&a[i]; } for(Point *now=&a[n],*last;*now!=s;){ last=now;now=now->next; ans+=(*now-*last).dis(); } printf("%.10lf\n",ans); } void init(){ double u,v,w; n=read();t.x=read();t.y=read(); s.x=s.y=0; for(int i=1;i<=n;i++){ a[i].x=read();a[i].y=read(); scanf("%lf",&w); u=atan2(s.y-a[i].y,s.x-a[i].x); v=atan2(t.y-a[i].y,t.x-a[i].x); if(NotInRange(w,u,v))a[i].direction=1; else a[i].direction=0; } sort(a+1,a+n+1); for(int i=1;i<=n;i++){ if(a[i].x<s.x||a[i].x>t.x)continue; a[++top]=a[i]; } a[++top]=t; n=top; } int main(){ init(); work(); return 0; }