Link
Solve
话说这道题挺良心的,算法在题目上都写出来了,我们就从凸包来考虑。
我们发现有圆的地方很难处理,画了几个图后发现,相比之下,圆的地方加起来就是一个整圆,问题是怎么来证明。
这里借用一下神仙jun头吉吉的图
我们观察到多出来的部分和圆肯定是相切的,比如(DK)切与圆(C),所以(∠BCD+∠BZD=180°)
多边形内角和为(sumlimits_{i=1}^nalpha_i=180 imes (n-2))
所以所有圆心角之和为$180 imes n - sumlimits_{i=1}^nalpha_i =180 imes n -180 imes (n-2) = 360 = 2pi $
答案即为一个圆的周长+圆心构成的凸包的周长。
所以这道题就和板子一样了
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,top,m;
double ans=0,A,B,R,l,phi;
struct AS{
double x,y;
}a[maxn],p[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
double check(AS A1,AS A2,AS B1,AS B2){
return (A2.x-A1.x)*(B2.y-B1.y)-(B2.x-B1.x)*(A2.y-A1.y);
}
double d(AS A,AS B){
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
bool cmp(AS x,AS y){
double tmp=check(a[1],x,a[1],y);
if(tmp>0)return 1;
if(tmp==0&&(d(a[1],x)<d(a[1],y)))return 1;
return 0;
}
void add(double x,double y){
n++;
a[n].x=x;a[n].y=y;
if(a[n].y<a[1].y)swap(a[1],a[n]);
}
int main(){
freopen("P3829.in","r",stdin);
freopen("P3829.out","w",stdout);
scanf("%d%lf%lf%lf",&m,&A,&B,&R);A-=2*R;B-=2*R;
l=sqrt(A*A+B*B)/2;
phi=atan(A/B);
for(int i=1;i<=m;i++){
double x,y,theta;
scanf("%lf%lf%lf",&x,&y,&theta);
double dx=cos(theta+phi)*l;
double dy=sin(theta+phi)*l;
add(x+dx,y+dy);
add(x-dx,y-dy);
dx=cos(theta-phi)*l;
dy=sin(theta-phi)*l;
add(x+dx,y+dy);
add(x-dx,y-dy);
}
sort(a+2,a+1+n,cmp);
p[top=1]=a[1];
for(int i=2;i<=n;i++){
while(top>1&&check(p[top-1],p[top],p[top],a[i])<=0)top--;
top++;
p[top]=a[i];
}
p[++top]=p[1];
for(int i=1;i<top;i++){
ans+=d(p[i],p[i+1]);
}
printf("%.2lf
",ans+3.141592653589793*2*R);
return 0;
}