Problem:
Score: 300 points

Problem Statement

Consider an analog clock whose hour and minute hands are A and B centimeters long, respectively.

An endpoint of the hour hand and an endpoint of the minute hand are fixed at the same point, around which each hand rotates clockwise at constant angular velocity. It takes the hour and minute hands 12 hours and 1 hour to make one full rotation, respectively.

At 0 o'clock, the two hands overlap each other. H hours and M minutes later, what is the distance in centimeters between the unfixed endpoints of the hands?

Constraints

All values in input are integers.

1 \leq A, B \leq 1000

0 \leq H \leq 11

0 \leq M \leq 59

Input

Input is given from Standard Input in the following format:

A B H M

Output

Print the answer without units. Your output will be accepted when its absolute or relative error from the correct value is at most 10^{-9}.

Sample Input 1

3 4 9 0

Sample Output 1

5.00000000000000000000

The two hands will be in the positions shown in the figure below, so the answer is 5 centimeters.

Sample Input 2

3 4 10 40

Sample Output 2

4.56425719433005567605

The two hands will be in the positions shown in the figure below. Note that each hand always rotates at constant angular velocity.

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using static System.Console;
using static System.Math;
using static MyIO;
using static MyUtil;

using static Geometory;
using Vector = Geometory.Point;
using Line = Geometory.Segment;
using Polygon = System.Collections.Generic.List<Geometory.Point>;

public class C { public static void Main() => (new Solver()).Solve(); }

public class Solver
{
	public void Solve()
	{
		var A = GetDouble();
		var B = GetDouble();
		var H = GetDouble();
		var M = GetDouble();

		var r1 = - 2.0 * Math.PI * (H / 12.0 + M / 720.0);
		var r2 = - 2.0 * Math.PI * (M / 60.0);
		var v1 = Polar(A, r1);
		var v2 = Polar(B, r2);
		WriteLine($"{GetDistance(v1, v2):F12}");
	}
}

public static class Geometory
{
	public const double EPS = 1e-10;
	public static bool Equals(double a, double b) => Math.Abs(a - b) < EPS;

	public class Point
	{
		public double X;
		public double Y;		
		public Point(double x, double y)
		{
			X = x;
			Y = y;
		}
	
		public static Point operator+(Point p, Point q) => new Point(p.X + q.X, p.Y + q.Y);
		public static Point operator-(Point p, Point q) => new Point(p.X - q.X, p.Y - q.Y);
		public static Point operator*(Point p, double a) => new Point(a * p.X, a * p.Y);
		public static Point operator*(double a, Point p) => new Point(a * p.X, a * p.Y);
		public static Point operator/(Point p, double a) => new Point(p.X / a, p.Y / a);
	}

	public class Segment
	{
		public Point P1;
		public Point P2;
		public Segment(Point p1, Point p2)
		{
			P1 = p1;
			P2 = p2;
		}
	}

	public class Circle
	{
		public Point C;
		public double R;
		public Circle(Point c, double r)
		{
			C = c;
			R = r;
		}
	}

	public static double Abs(Vector a) => Math.Sqrt(Norm(a));
	public static double Norm(Vector a) => a.X * a.X + a.Y * a.Y;
	public static double Dot(Vector a, Vector b) => a.X * b.X + a.Y * b.Y;
	public static double Cross(Vector a, Vector b) => a.X * b.Y - a.Y * b.X;

	public static bool IsOrthogonal(Vector a, Vector b) => Equals(Dot(a, b), 0.0);
	public static bool IsOrthogonal(Point a1, Point a2, Point b1, Point b2) => IsOrthogonal(a1 - a2, b1 - b2);
	public static bool IsOrthogonal(Segment s1, Segment s2) => Equals(Dot(s1.P2 - s1.P1, s2.P2 - s2.P1), 0.0);
	public static bool IsParallel(Vector a, Vector b) => Equals(Cross(a, b), 0.0);
	public static bool IsParallel(Point a1, Point a2, Point b1, Point b2) => IsParallel(a1 - a2, b1 - b2);
	public static bool IsParallel(Segment s1, Segment s2) => Equals(Cross(s1.P2 - s1.P1, s2.P2 - s2.P1), 0.0);

	public static Point Project(Segment s, Point p)
	{
		Vector b = s.P2 - s.P1;
		double r = Dot(p - s.P1, b) / Norm(b);
		return s.P1 + b * r;
	}
	public static Point Reflect(Segment s, Point p) => p + (Project(s, p) - p) * 2.0;

	public static double GetDistance(Point a, Point b) => Abs(a - b);
	public static double GetDistanceLP(Line l, Point p) => Math.Abs(Cross(l.P2 - l.P1, p - l.P1) / Abs(l.P2 - l.P1));
	public static double GetDistanceSP(Segment s, Point p)
	{
		if(Dot(s.P2 - s.P1, p - s.P1) < 0.0) return Abs(p - s.P1);
		if(Dot(s.P1 - s.P2, p - s.P2) < 0.0) return Abs(p - s.P2);
		return GetDistanceLP(s, p);
	}
	public static double GetDistance(Segment s1, Segment s2)
	{
		if(Intersect(s1, s2)) return 0.0;
		return Math.Min(Math.Min(GetDistanceSP(s1, s2.P1), GetDistanceSP(s1, s2.P2)),
		                Math.Min(GetDistanceSP(s2, s1.P1), GetDistanceSP(s2, s1.P2)));
	}

	public const int COUNTER_CLOCKWISE = 1;
	public const int CLOCKWISE = -1;
	public const int ONLINE_BACK = 2;
	public const int ONLINE_FRONT = -2;
	public const int ON_SEGMENT = 0;
	public static int Ccw(Point p0, Point p1, Point p2)
	{
		Vector a = p1 - p0;
		Vector b = p2 - p0;
		if(Cross(a, b) > EPS) return COUNTER_CLOCKWISE;
		if(Cross(a, b) < -EPS) return CLOCKWISE;
		if(Dot(a, b) < -EPS) return ONLINE_BACK;
		if(Norm(a) < Norm(b)) return ONLINE_FRONT;
		return ON_SEGMENT;
	}
	public static bool Intersect(Point p1, Point p2, Point p3, Point p4)
	{
		return (Ccw(p1, p2, p3) * Ccw(p1, p2, p4) <= 0 && 
		        Ccw(p3, p4, p1) * Ccw(p3, p4, p2) <= 0);
	}
	public static bool Intersect(Segment s1, Segment s2) => Intersect(s1.P1, s1.P2, s2.P1, s2.P2);
	public static bool Intersect(Circle c, Line l) => GetDistanceLP(l, c.C) - c.R < EPS;
	public static bool Intersect(Circle c1, Circle c2) => GetDistance(c1.C, c2.C) - c1.R - c2.R < EPS;

	public static Point GetCrossPoint(Segment s1, Segment s2)
	{
		Vector b = s2.P2 - s2.P1;
		double d1 = Math.Abs(Cross(b, s1.P1 - s2.P1));
		double d2 = Math.Abs(Cross(b, s1.P2 - s2.P1));
		double t = d1 / (d1 + d2);
		return s1.P1 + (s1.P2 - s1.P1) * t;
	}
	public static Tuple<Point, Point> GetCrossPoints(Circle c, Line l)
	{
		if(!Intersect(c, l)) throw new Exception();
		Vector pr = Project(l, c.C);
		Vector e = (l.P2 - l.P1) / Abs(l.P2 - l.P1);
		double b = Math.Sqrt(c.R * c.R - Norm(pr - c.C));
		return Tuple.Create(pr + e * b, pr - e * b);
	}

	public static double Arg(Vector p) => Math.Atan2(p.Y, p.X);
	public static Vector Polar(double a, double r) => new Point(Math.Cos(r) * a, Math.Sin(r) * a);
	public static Tuple<Point, Point> GetCrossPoints(Circle c1, Circle c2)
	{
		if(!Intersect(c1, c2)) throw new Exception();
		double d = Abs(c1.C - c2.C);
		double a = Math.Acos((c1.R * c1.R + d * d - c2.R * c2.R) / (2 * c1.R * d));
		double t = Arg(c2.C - c1.C);
		return Tuple.Create(c1.C + Polar(c1.R, t + a), c1.C + Polar(c1.R, t - a));
	}

	/* IN: 2, ON: 1, OUT: 0 */
	public static int Contains(Polygon g, Point p)
	{
		int n = g.Count;
		bool x = false;
		for(int i = 0; i < n; i++)
		{
			Point a = g[i] - p;
			Point b = g[(i + 1) % n] - p;
			if(Math.Abs(Cross(a, b)) < EPS && Dot(a, b) < EPS) return 1;
			if(a.Y > b.Y) swap(ref a, ref b);
			if(a.Y < EPS && EPS < b.Y && Cross(a, b) > EPS) x = !x;
		}
		return (x ? 2 : 0);
	}

	public static Polygon AndrewScan(Polygon s, bool containsOnSegment = false)
	{
		s.Sort((a, b) => !Equals(a.X, b.X) ? a.X.CompareTo(b.X) : a.Y.CompareTo(b.Y));
		if(s.Count < 3) return s;

		var u = new List<Point>();
		u.Add(s[0]);
		u.Add(s[1]);
		for(int i = 2; i < s.Count; i++)
		{
			if(containsOnSegment)
			{
				for(int n = u.Count; n >= 2 && Ccw(u[n - 2], u[n - 1], s[i]) == COUNTER_CLOCKWISE; n--)
					u.RemoveAt(u.Count - 1);  // O(1) ?	
			}
			else
			{
				for(int n = u.Count; n >= 2 && Ccw(u[n - 2], u[n - 1], s[i]) != CLOCKWISE; n--)
					u.RemoveAt(u.Count - 1);  // O(1) ?				
			}
			u.Add(s[i]);
		}

		var l = new List<Point>();
		l.Add(s[s.Count - 1]);
		l.Add(s[s.Count - 2]);
		for(int i = s.Count - 3; i >= 0; i--)
		{
			if(containsOnSegment)
			{
				for(int n = l.Count; n >= 2 && Ccw(l[n - 2], l[n - 1], s[i]) == COUNTER_CLOCKWISE; n--)
					l.RemoveAt(l.Count - 1);  // O(1) ?	
			}
			else
			{
				for(int n = l.Count; n >= 2 && Ccw(l[n - 2], l[n - 1], s[i]) != CLOCKWISE; n--)
					l.RemoveAt(l.Count - 1);  // O(1) ?				
			}
			l.Add(s[i]);
		}
		
		l.Reverse();
		for(int i = u.Count - 2; i >= 1; i--)
			l.Add(u[i]);
		
		return l;
	}
}

public static class MyIO
{
	private static string[] args = new string[0];
	private static int cnt = 0;
	private static IEnumerable<string> getArgs(long N) => Range(0, N).Select(_ => getArg());
	private static string getArg()
	{
		if(cnt == args.Length) { args = Console.ReadLine().Split(); cnt = 0; }
		return args[cnt++];
	}

	public static int GetInt() => int.Parse(getArg());
	public static long GetLong() => long.Parse(getArg());
	public static double GetDouble() => double.Parse(getArg());
	public static decimal GetDecimal() => decimal.Parse(getArg());
	public static string GetString() => getArg();
	public static char GetChar() => getArg()[0];
	public static int[] GetInts(long N) => getArgs(N).Select(int.Parse).ToArray();
	public static long[] GetLongs(long N) => getArgs(N).Select(long.Parse).ToArray();
	public static double[] GetDoubles(long N) => getArgs(N).Select(double.Parse).ToArray();
	public static decimal[] GetDecimals(long N) => getArgs(N).Select(decimal.Parse).ToArray();
	public static string[] GetStrings(long N) => getArgs(N).ToArray();
}

public static class MyUtil
{
	public static void chmax<T>(ref T x, T y) where T : IComparable<T> { if(x.CompareTo(y) < 0) x = y; }
	public static void chmin<T>(ref T x, T y) where T : IComparable<T> { if(x.CompareTo(y) > 0)	x = y; }
	public static void swap<T>(ref T x, ref T y) { T tmp = x; x = y; y = tmp; }
	public static long rightShift(long x, long y) => (x >> (int)y);
	public static long leftShift(long x, long y) => (x << (int)y);
	public static bool contains(long s, long x) => (rightShift(s, x) & 1L) == 1L;
	public static long gcd(long x, long y) => (y == 0) ? x : gcd(y, x % y);
	public static long lcm(long x, long y) => (x / gcd(x,y)) * y;	
	public static IEnumerable<int> Range(long start, long count) => Enumerable.Range((int)start, (int)count);
	public static void Sort(this List<string> source) => source.Sort(StringComparer.Ordinal);
}