题目大意
给定一个边长为$1$的正$n$边形,另有一个正$m$边形,两个多边形的中心重合,求正$m$边形的最小边长,使得正$n$边形能完整的被正$m$边形覆盖。
题解
这道题部分分给的很良心而且有用处。
对于$n|m$的情况,$n$的点数是$m$点数的约数,所以我们可以钦定让正$n$边形的顶点与正$m$边形的若干顶点重合,即钦定它们拥有同一个外接圆,不难证明这一定是最优且合法的方案。
对于$m|n$的情况,$m$的边数是$n$点数的约数,所以我们可以钦定让正$n$边形的边与正$m$边形的若干边重合,即钦定它们拥有同一个内切圆,同样不难证明这一定是最优且合法的方案。
考虑都不满足的情况。
由于正$n$边形任意旋转$frac{2pi}{m}$与正$m$边形相对位置不变,所以一定还能恰好被覆盖。
因此有一个非常有意思的结论,我们可以直接这正$n$边形被一个正$lcm(n,m)$边形覆盖,再钦定这个正多边形被正$m$边形覆盖。
其中这这两个部分恰好就是部分分的两个字问题,因为一定有$n|lcm(n,m),m|lcm(n,m)$,答案分开计算再乘起来即可。
复杂度$O(log n+log m)$。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long using namespace std; LL read(){ LL nm=0,fh=1; LL cw=getchar(); for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm*fh; } LL gcd(LL x,LL y){return y?gcd(y,x%y):x;} const long double pi=acos(-1); long double ans; LL n,m,K; long double calc(LL l1,LL l2){ if(l1==l2) return 1.0; long double t1=l1*1.0,t2=l2*1.0; if(l1%l2==0) return tan(pi/t2)/tan(pi/t1); else return sin(pi/t2)/sin(pi/t1); } int main(){ n=read(),m=read(),K=n*m/gcd(n,m); ans=calc(n,K)*calc(K,m); printf("%.61Lf ",ans); return 0; }