#include <algorithm>
#include <cstdio>
#include <cmath>
#define eps 1e-12
#define maxn 100010
#define maxm 400010
#define calc(a, b, c) (cross((b)-(a),(c)-(a)))
using namespace std;
const double PI = acos(-1);
struct P{
double x, y;
P(double x = 0.0, double y = 0.0):x(x), y(y) {}
}p[maxm];
P operator + (P a, P b) {return (P){a.x + b.x, a.y + b.y};}
P operator - (P a, P b) {return (P){a.x - b.x, a.y - b.y};}
P operator - (P a) {return (P){-a.x, -a.y};}
P operator * (P a, double b) {return (P){a.x * b, a.y * b};} // 数乘
bool operator < (const P& a, const P& b) {
return a.x==b.x?a.y<b.y:a.x<b.x;
}
double dot(P a, P b) {return a.x*b.x+a.y*b.y;} // 点积
double cross(P a, P b) {return a.x*b.y-a.y*b.x;} // 叉积
double abs(P a) {return sqrt(a.x*a.x+a.y*a.y);} // 取模
P rotate(P a, double t) { // 旋转
double c = cos(t), s = sin(t);
return (P) {a.x*c-a.y*s, a.x*s+a.y*c};
}
int q[maxn];
int main() {
int n, c = 0;
double a, b, r, x, y, t;
scanf("%d%lf%lf%lf", &n, &b, &a, &r);
a /= 2.0, b /= 2.0; // 取得半长和半宽
for(int i = 1; i <= n; i++) {
scanf("%lf%lf%lf", &x, &y, &t);
x += eps, y += eps, t += eps; // 扰动,避免出现除0或者NaN
P _ = (P){x, y}; // 中心
p[++c] = rotate((P){a-r, b-r}, t) + _; // 先旋转再加中心
p[++c] = rotate((P){r-a, b-r}, t) + _;
p[++c] = rotate((P){r-a, r-b}, t) + _;
p[++c] = rotate((P){a-r, r-b}, t) + _;
}
sort(p+1, p+c+1); // x-y 排序
int T = 0;
for(int i = 1; i <= c; i++) { // 下凸壳
while(T>1&&calc(p[q[T-1]],p[q[T]],p[i])<=0)T--;
q[++T] = i;
}
int tmp = T;
for(int i = c - 1; i; i--) { // 上凸壳
while(T>tmp&&calc(p[q[T-1]],p[q[T]],p[i])<=0)T--;
q[++T] = i;
}
double ans = 2 * PI * r; // 加上一周
for(int i = 1; i < T; i++) ans += abs(p[q[i]]-p[q[i+1]]);
printf("%.2lf", ans);
return 0;
}
P3829 [SHOI2012] 信用卡凸包
最新推荐文章于 2024-05-30 20:15:33 发布