[洛谷P3829][SHOI2012]信用卡凸包

时间:2023-03-10 03:53:18
[洛谷P3829][SHOI2012]信用卡凸包

题目大意:有$n$张一模一样的信用卡,每个角进行了圆滑处理,问这些卡组成的“凸包”的周长

题解:发现是圆滑处理的圆心围成的凸包加上一个圆周即可

卡点:输入长宽弄反,然后以为是卡精

C++ Code:

#include <algorithm>
#include <cstdio>
#include <cmath>
#include <iomanip>
#include <iostream>
#define maxn 10010
const double Pi = acosl(-1); struct Point {
long double x, y;
Point() { }
Point(long double __x, long double __y) : x(__x), y(__y) { } inline long double operator ^ (const Point &rhs) const {
return x * rhs.y - y * rhs.x;
}
inline Point operator + (const Point &rhs) const {
return Point(x + rhs.x, y + rhs.y);
}
inline Point operator - (const Point &rhs) const {
return Point(x - rhs.x, y - rhs.y);
}
inline Point rotate(long double theta) {
const long double Sin = sinl(theta), Cos = cosl(theta);
return Point(x * Cos - y * Sin, x * Sin + y * Cos);
}
} s[maxn << 2], O, v[maxn << 2];
inline long double abs2(const Point &x) { return x.x * x.x + x.y * x.y; }
inline long double dis(const Point &lhs, const Point &rhs) { return sqrtl(abs2(lhs - rhs)); }
inline long double det(const Point &O, const Point &lhs, const Point &rhs) {
return (lhs - O) ^ (rhs - O);
}
inline bool cmp(const Point &x, const Point &y) {
static Point X, Y; X = x - O, Y = y - O;
static long double tmp; tmp = X ^ Y;
return (tmp > 0) || (tmp == 0 && abs2(X) < abs2(Y));
} int n, tot;
long double ans, A, B, R;
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
std::cin >> n >> A >> B >> R; ans = 2 * R * Pi;
A /= 2, B /= 2, A -= R, B -= R;
for (int i = 0; i < n; ++i) {
static long double x, y, theta;
std::cin >> x >> y >> theta;
const Point t1 = Point(B, A).rotate(theta), t2 = Point(B, -A).rotate(theta), O(x, y);
s[tot++] = O - t1, s[tot++] = O + t1;
s[tot++] = O - t2, s[tot++] = O + t2;
}
int miny = 0;
for (int i = 0; i < tot; ++i)
if (s[i].y < s[miny].y || (s[i].y == s[miny].y && s[i].x < s[miny].x)) miny = i;
std::swap(s[0], s[miny]); O = s[0];
std::sort(s + 1, s + tot, cmp);
n = tot, tot = 3;
v[0] = s[0], v[1] = s[1], v[2] = s[2];
for (int i = 3; i < n; ++i) {
Point *a = v + tot - 2, *b = v + tot - 1;
while (tot > 2 && det(*a, *b, s[i]) <= 0) {
--tot, --a, --b;
}
v[tot++] = s[i];
}
for (int i = 1; i < tot; ++i) ans += dis(v[i - 1], v[i]);
ans += dis(v[0], v[tot - 1]);
std::cout << std::fixed << std::setprecision(2) << ans << '\n';
return 0;
}