Official

B - Counterclockwise Rotation Editorial by m_99


概要

本問は以下の処理を順に行うことで解くことが出来ます。

  1. \((a,b)\) の「原点からの距離」と「原点から \((a,b)\) までを結ぶ線分の角度」を求める
  2. \((a,b)\) の角度を \(d\) 度増やした座標を求める

都合上、2→ 1 の順に解説を行います。

三角関数

1番目のステップで求められた原点からの距離を \(r\)、角度を \(\theta\) とします。\(\theta\)\(d\) 度増やした角度を \(\theta '\) とします。ここでの目的は、原点からの距離が \(r\) で角度が \(\theta '\) である点の座標を求めることです。
\(r=1\) の場合の角度 \(\theta\) に対する \(x,y\) 座標は三角関数 \(\cos \theta, \sin \theta\) の定義そのものです。また、C++を始めとする多くのプログラミング言語では以下のような記述でその値を得ることが出来ます。

x = cos(theta);
y = sin(theta);

\(r\)\(1\) とは限らない場合については、上記のように求められた \(x,y\) 座標を \(r\) 倍すれば良いです。

逆三角関数

1番目のステップでは、座標 \((a,b)\) から原点からの距離 \(r\) と角度 \(\theta\) を求める必要があります。
\(r\)\(r=\sqrt{a^2+b^2}\) として求められます。
\(\theta\) は、三角関数の逆関数を使うことで求められます。ここで、単純に \(\sin \theta, \cos \theta, \tan \theta\) の逆関数を用いて \(\theta\) を求めようとすると場合分けが生じて大変なことになると思われますが、C++を始めとする多くのプログラミング言語では関数atan2(y,x)を用いて以下のように \(\theta\) を求めることが出来ます。

theta = atan2(b,a);

以上より、\(r,\theta\) が求められました。

注意点

  • 本問で与えられる角度は度数法ですが、C++等のプログラム上で扱われる(三角関数等の引数や戻り値として想定される)角度は弧度法です。そのため、\(d' = \frac{d\times \pi}{180}\) 等と変換して処理する必要があります。
  • 本問では \((a,b)=(0,0)\) である場合がありますが、\(\mathrm{atan2}(0,0)\) の値は数学的に定義されません。お使いのプログラミング言語でatan2(0,0)がなんらかの値を \(\theta\) として返す場合はそれで計算された座標を \(r=0\) 倍するので問題ない(実装例もそういうものとしている)のですが、これが未定義だったりエラーになったりする場合は場合分けが必要です。
  • 出力する桁数をデフォルトの状態から変更しないと、計算自体は正しいにも関わらず出力された桁数が少ないせいで精度が不十分となる可能性があります。

実装例(C++)

#include <bits/stdc++.h>
using namespace std;

int main() {
    
	double a,b,d;
	cin>>a>>b>>d;

	double r = hypot(a,b);
	double theta = atan2(b,a);

	theta += d * acos(-1.0) / 180.0;

	double x = cos(theta) * r;
	double y = sin(theta) * r;

	cout<<fixed<<setprecision(10)<<x<<' '<<y<<endl;

	return 0;
	
}

posted:
last update: