Codeforces 198(#125 Div1) C. Delivering Carcinogen
問題
座標平面の原点が恒星。その周囲を円軌道で惑星が反時計回りに速度vpで周っていて、
惑星はt = 0のとき(xp, yp)にいる。
宇宙船が(x, y)にいて、宇宙船は好きな方向に速度vで動くことができる。
太陽から距離r以内に入ると熱くて死ぬ。宇宙船は最短で何秒で惑星に着けるか求めよ。
制約条件
入力は1万以下の非負整数
vp<v
方針
宇宙船のほうが速いので、ある時間tで惑星に着けるなら、t≦t'な時間t'でも惑星に着ける(tで着いて後ろに密着してればいいので)
なので、tについて二分探索する。
ある時間tを決めたとき、惑星は円運動なので位置はすぐわかる。
その位置まで、宇宙船が最短距離で移動したとき、t以内の時間でいければよい。
円を迂回する二点の最短距離は、二点の線分に円がかぶらないときは単なる直線距離。
そうでない場合を考える。二点をA, B, 円をCとする。
AからCへ引いた接線の接点まで直線で行って、BからCへ引いた接線の接点まで円周上を行って、接点からは離れて直線でBまで行くのが最短。
円と接線はライブラリを用意しておくか、適当に方程式を解くか。
ソースコード
double xp, yp, vp, x, y, v, r; P s, t, o(0, 0); G g; double calc(const P &p){ if(distanceSP(L(s, p), o) + EPS > r) return abs(s - p); G h = tanCP(o, r, p); int c = ccw(s, p, o); if(c == 0) c = -1; int i, j; for(i = 0; i < g.size() && ccw(s, p, g[i]) == c; i++); for(j = 0; j < h.size() && ccw(s, p, h[j]) == c; j++); double a = arg(g[i]), b = arg(h[j]); if(a > b) b += 2 * PI; a = b - a; if(a > PI) a = 2 * PI - a; return r * a + abs(s - g[i]) + abs(p - h[j]); } int main(){ cin >> xp >> yp >> vp >> x >> y >> v >> r; s = P(x, y); t = P(xp, yp); g = tanCP(o, r, s); double w = vp / abs(t); double lo = 0, hi = 1e8, mid; rep(it, 100){ mid = (lo + hi) / 2; P p = t * P(cos(mid * w), sin(mid * w)); if(calc(p) < mid * v) hi = mid; else lo = mid; } printf("%.20f\n", lo); return 0; }