蛋糕

题目大意

给定一个边长为$1$的正$n$边形,另有一个正$m$边形,两个多边形的中心重合,求正$m$边形的最小边长,使得正$n$边形能完整的被正$m$边形覆盖。

题解

这道题部分分给的很良心而且有用处。

对于$n|m$的情况,$n$的点数是$m$点数的约数,所以我们可以钦定让正$n$边形的顶点与正$m$边形的若干顶点重合,即钦定它们拥有同一个外接圆,不难证明这一定是最优且合法的方案。

对于$m|n$的情况,$m$的边数是$n$点数的约数,所以我们可以钦定让正$n$边形的边与正$m$边形的若干边重合,即钦定它们拥有同一个内切圆,同样不难证明这一定是最优且合法的方案。

考虑都不满足的情况。

由于正$n$边形任意旋转$\frac{2\pi}{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\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/OYJason/p/9768483.html