Maximum Rotating Rectangle Shadow
National Olympiad — Municipal round (2016 season)
Submission name: shadow_new.cpp
Problem summary
Two identical a by b rectangular sheets rotate about their common center in a horizontal plane. Find the maximum union area, which equals their shadow area under vertical sunlight.
Input
Positive integers a b.
Output
Maximum area rounded to exactly three digits after the decimal point.
Constraints
1 ≤ a,b ≤ 10000.
Worked example
Official sample; other valid outputs may exist.
Input
11 9
Output
117.258
Solution analysis
- Assume a≤b and let θ be the relative angle in [0,π/2]. At θ=π/2 the union area is 2ab−a². For θ≥2 arctan(a/b), the intersection is a parallelogram of area a²/sin θ, so the union increases toward that endpoint. It remains to optimize the earlier angles.
- Set t=tan(θ/2), so 0≤t≤a/b. Removing the two pairs of corner triangles from one rectangle shows that the union is U(t)=ab+t((b−at)²+(a−bt)²)/(2(1−t²)). For a=b,t=1 use its limiting value ab. The numerator of U′, apart from a positive factor, is H(t)=(a²+b²)(1+4t²−t⁴)−8abt.
- To find every stationary point, first split H at its unique minimum on [0,1]. Its derivative is 4(a²+b²)(2t−t³)−8ab; its first zero lies in [0,sqrt(2/3)], where it increases strictly. After that zero H increases through t=1. Bisect H on each resulting monotone interval within [0,a/b], evaluate all its roots and interval endpoints, and compare with 2ab−a². For 9 by 11 rectangles this gives 117.258.
Why it works
The intersection geometry has exactly the corner-triangle and parallelogram regimes described. Summing the four removed triangle areas gives U. Differentiation gives H. Since H′ increases up to sqrt(2/3), then decreases to H′(1)=4(a−b)²≥0, it has exactly one interior sign change, so H decreases and then increases. The two bisection intervals therefore contain every zero of U′. A continuous function on the compact angle range achieves its maximum at an endpoint or stationary point. Evaluating these candidates and the best parallelogram endpoint yields the global maximum.
Watch out. A right-angle crossing is not always optimal. A single ternary search across all angles is not justified. Use long double and evaluate the square endpoint by its limit.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
long double a,b;
cin>>a>>b;
if(a>b){
swap(a,b);
}
long double sum=a*a+b*b;
long double product=a*b;
auto h=[&](long double t){
return sum*(1+4*t*t-t*t*t*t)-8*product*t;
};
auto derivative=[&](long double t){
return 4*sum*(2*t-t*t*t)-8*product;
};
auto area=[&](long double t){
if(t>=1){
return product;
}
long double x=b-a*t;
long double y=a-b*t;
return product+t*(x*x+y*y)/(2*(1-t*t));
};
long double left=0,right=sqrtl(2.0L/3);
// Find the unique minimum of H in [0,1].
for(int iteration=0;iteration<100;++iteration){
long double mid=(left+right)/2;
if(derivative(mid)<0){
left=mid;
}
else{
right=mid;
}
}
long double limit=a/b;
long double split=min(limit,(left+right)/2);
long double answer=max(2*product-a*a,area(limit));
answer=max(answer,area(split));
long double endpoints[3]={0,split,limit};
for(int interval=0;interval<2;++interval){
left=endpoints[interval];
right=endpoints[interval+1];
bool leftPositive=h(left)>0;
if(leftPositive==(h(right)>0)){
continue;
}
for(int iteration=0;iteration<100;++iteration){
long double mid=(left+right)/2;
if((h(mid)>0)==leftPositive){
left=mid;
}
else{
right=mid;
}
}
answer=max(answer,area((left+right)/2));
}
cout<<fixed<<setprecision(3)<<answer<<'\n';
}