題目大意:有n個人進行鐵人三項比賽,對於這三種運動,每個人都有一個固定的速度,但是每種運動的長度是多少並不知道。現在問裁判可不可以通過調整這三項運動的長度來使某一個人贏得比賽。
思路:考慮現在我們想讓一個人贏的時候,這個人的三個速度分別為v1,v2,v3,想讓所有人都輸給他,設某一個人的三個速度是v1',v2',v3'。設三項的比賽的長度為l1,l2,l3。那麼不難得到如下方程:l1 / v1 + l2 / v2 + l3 / v3 < l1 / v1' + l2 / v2' + l3 / v3'。
但是這個方程有三個未知數,這是啥,根本沒法處理。其實這個題只要求我們求出能否有解,那麼對於具體的值我們並不關注。如果一個解X,Y,Z可以讓一個人贏所有的人,那麼X*K,Y*K,Z*K也可以讓這個人贏所有的人。所以我們確定一個l值並不會影響答案的正確性。所以假設l3 = 1,那麼l3 / v3和l3 / v3'就是兩個定值了。
原方程就變成了:(為了方便理解,設x = l1,y = l2)x * (v1' - v1) / (v1 * v1') + y * (v2' - v2) / (v2 * v2') + k - k' < 0.
這個式子中,我們只有xy不知道,剩下的都是常量。這就是一個關於x和y的一個半平面。找到所有的半平面,然後判斷內核是否存在,就是答案。
數據范圍很小,用O(n^2)的半平面交應該也可以過。
然而我並沒有過這個題。。這個題卡精度簡直令人不忍直視,從網上搞到數據之後用cena測,一共25個點,就是有兩個點死活過不去。。心裡AC了。。
CODE(未AC,謹慎提交):
#include#include #include #include #include #define MAX 10010 #define EPS 1e-16 #define INF (1ll << 32) using namespace std; #define DCMP(a) (fabs(a) < EPS) struct Complex{ double v1,v2,v3; void Read() { scanf("%lf%lf%lf",&v1,&v2,&v3); } }src[MAX]; struct Point{ double x,y; Point(double _ = .0,double __ = .0):x(_),y(__) {} Point operator +(const Point &a)const { return Point(x + a.x,y + a.y); } Point operator -(const Point &a)const { return Point(x - a.x,y - a.y); } Point operator *(double a)const { return Point(x * a,y * a); } }p[MAX]; struct Line{ Point p,v; double alpha; bool operator <(const Line &a)const { return alpha < a.alpha; } Line(Point _,Point __):p(_),v(__) { alpha = atan2(v.y,v.x); } Line() {} }line[MAX],q[MAX]; int cnt,lines; inline double Cross(const Point &a,const Point &b) { return a.x * b.y - a.y * b.x; } inline bool OnLeft(const Line &l,const Point &p) { return Cross(l.v,p - l.p) > 0; } inline void MakeLine(const Complex &win,const Complex &lose) { double A = (lose.v1 - win.v1) / (win.v1 * lose.v1); double B = (lose.v2 - win.v2) / (win.v2 * lose.v2); double C = (lose.v3 - win.v3) / (win.v3 * lose.v3); if(DCMP(A) && DCMP(B) && C < EPS) throw false; if(DCMP(B)) B = EPS; line[++lines] = Line(Point(.0,-C / B),Point(-B,A)); } inline void Initialize() { line[++lines] = Line(Point(0,0),Point(1,0)); line[++lines] = Line(Point(INF,0),Point(0,1)); line[++lines] = Line(Point(INF,INF),Point(-1,0)); line[++lines] = Line(Point(0,INF),Point(0,-1)); } inline Point GetIntersection(const Line &a,const Line &b) { Point u = a.p - b.p; double temp = Cross(b.v,u) / Cross(a.v,b.v); return a.p + a.v * temp; } inline bool HalfplaneIntersection() { int front = 1,tail = 1; q[1] = line[1]; for(int i = 2;i <= lines; ++i) { while(front < tail && !OnLeft(line[i],p[tail - 1])) --tail; while(front < tail && !OnLeft(line[i],p[front])) ++front; if(DCMP(Cross(line[i].v,q[tail].v))) q[tail] = OnLeft(q[tail],line[i].p) ? line[i]:q[tail]; else q[++tail] = line[i]; if(front < tail) p[tail - 1] = GetIntersection(q[tail],q[tail - 1]); } while(front < tail && !OnLeft(q[front],p[tail - 1])) --tail; if(tail - front <= 1) return false; double re = Cross(tail,front); for(int i = front; i < tail; ++i) re += Cross(p[i],p[i + 1]); return !DCMP(re); } int main() { cin >> cnt; for(int i = 1; i <= cnt; ++i) src[i].Read(); for(int i = 1; i <= cnt; ++i) { lines = 0; try{ for(int j = 1; j <= cnt; ++j) { if(i == j) continue; MakeLine(src[i],src[j]); } } catch(bool flag) { puts("No"); continue; } Initialize(); sort(line + 1,line + lines + 1); if(HalfplaneIntersection()) puts("Yes"); else puts("No"); } return 0; }