Strip
National Olympiad — Regional round (2013 season)
Submission name: band.cpp
Problem summary
Cut the longest possible single rectangular strip of fixed width c from an a by b rectangle. The strip may be rotated but cannot be assembled from separate pieces.
Input
The integers a b c.
Output
The maximum length, rounded and formatted to two decimals.
Constraints
0 < c < b < a < 10000.
Worked example
Official statement sample.
Input
90 50 15
Output
91.54
Solution analysis
- A length L and width c rotated through θ have bounding-box dimensions L cosθ+c sinθ and L sinθ+c cosθ. Reflection allows θ in [0,π/2]. The axis-aligned length a always fits, so search only L≥a.
- For L>a, write R=sqrt(L²+c²) and φ=atan(c/L). The horizontal inequality is R cos(θ−φ)≤a, forcing θ≥φ+acos(a/R). The vertical inequality is R sin(θ+φ)≤b. Since at θ=π/2 its value is L>b, its allowed part in this quadrant is θ≤asin(b/R)−φ. Thus L fits exactly when these lower and upper angle bounds overlap.
- Feasibility is monotone in L: shortening a fitting rectangle preserves its orientation and fit. Binary search from a to the sheet diagonal. For the sample this yields about 91.54, a small improvement over the horizontal length 90.
Why it works
The projection formulas are necessary and sufficient for a rotated rectangle to fit after translation. For L>a>b>c the trigonometric inequalities have exactly the allowed angle intervals derived above; their intersection is nonempty precisely for a feasible strip. Binary search therefore converges to the maximum length.
Watch out. Do not ternary-search the whole orientation range without proving unimodality. The axis-aligned endpoint remains feasible even when no longer rotated strip fits.
Commented C++17 solution
An independently written complete program with standard headers.
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
int main(){
long double a,b,c;
cin>>a>>b>>c;
long double low=a;
long double high=hypotl(a,b);
for(int iteration=0;iteration<100;++iteration){
long double length=(low+high)/2;
long double radius=hypotl(length,c);
long double phi=atanl(c/length);
// Feasibility means the two allowable orientation intervals overlap.
long double from=phi+acosl(a/radius);
long double to=asinl(b/radius)-phi;
if(from<=to){
low=length;
}
else{
high=length;
}
}
cout<<fixed<<setprecision(2)<<low<<'\n';
}