kmjp's blog

競技プログラミング参加記です

DISCO presents ディスカバリーチャンネル コードコンテスト2019 本戦 : C - 光の反射 (Reflection of Light)

これ幾何としてはライブラリもいらないしさほど難しくないと思うんだけど、なんでこんな正解者少ないんだろう…。
https://atcoder.jp/contests/ddcc2019-final/tasks/ddcc2019_final_c

問題

円形のフィールド内に、さらに円柱が1個ある。
フィールド中、円柱外に光源があるとする。光源から出た光は基本的に直進するが、途中任意の位置で任意の角度に向きを変える、ということがK回まで行える。
照らされるフィールドの外壁の割合を求めよ。

解法

光源から、円柱の左側に接するように進み、外周スレスレで再度同様に向きを変える、という光と、逆に右側に接するように進む光を考えればよい。
線分と円の交差判定は二次方程式を解いてもよいが、以下では二分探索で横着している。

double LX[11],LY[11];
double RX[11],RY[11];
double PX,PY,PR,SX,SY;
int K;

double angle(double ax,double ay,double bx,double by) {
	double ret=atan2(by,bx)-atan2(ay,ax);
	ret/=8*atan(1);
	if(ret<0) ret+=1;
	return ret;
}

pair<double,double> hoge(double X,double Y,int dir) {
	double r=hypot(X-PX,Y-PY);
	double deg=atan2(PY-Y,PX-X)+dir*asin(PR/r);
	double dx=cos(deg);
	double dy=sin(deg);
	
	int i;
	double di=2;
	FOR(i,100) {
		double nx=X+di*dx;
		double ny=Y+di*dy;
		if(ny*ny+nx*nx<=1) {
			X=nx;
			Y=ny;
		}
		di/=2;
	}
	
	return {X,Y};
	
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>PX>>PY>>PR;
	cin>>SX>>SY>>K;
	
	auto a=hoge(SX,SY,1);
	LX[0]=a.first,LY[0]=a.second;
	a=hoge(SX,SY,-1);
	RX[0]=a.first,RY[0]=a.second;
	
	
	double ret=angle(LX[0],LY[0],RX[0],RY[0]);
	_P("%.12lf\n",min(1.0,ret));
	FOR(i,K) {
		a=hoge(LX[i],LY[i],1);
		LX[i+1]=a.first,LY[i+1]=a.second;
		a=hoge(RX[i],RY[i],-1);
		RX[i+1]=a.first,RY[i+1]=a.second;
		ret+=angle(LX[i+1],LY[i+1],LX[i],LY[i]);
		ret+=angle(RX[i],RY[i],RX[i+1],RY[i+1]);
		_P("%.12lf\n",min(1.0,ret));
	}
	
	
}

まとめ

幾何はライブラリがないときつい、みたいな先入観があるのかな…?