P3829 [SHOI2012]信用卡凸包
还是不会计算几何。。
显然你需要 rotate 一下向量,学到许多。。
最后加上圆的周长就好了,因为并起来的部分是一个正圆。
// by Isaunoya
#include<bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
const double eps = 1e-4;
struct Vector {
double x, y;
Vector (double _x = 0, double _y = 0) { x = _x, y = _y; }
Vector operator + (const Vector & rhs) const { return Vector(x + rhs.x, y + rhs.y); }
Vector operator - (const Vector & rhs) const { return Vector(x - rhs.x, y - rhs.y); }
double operator ^ (const Vector & rhs) const { return x * rhs.y - y * rhs.x; }
double dis() { return sqrt(x * x + y * y); }
bool operator < (const Vector & rhs) const { return x == rhs.x ? y < rhs.y : x < rhs.x; }
};
Vector rtt(Vector x, double tht) { return Vector(x.x * cos(tht) - x.y * sin(tht), x.x * sin(tht) + x.y * cos(tht)); }
int n; double a, b, r;
vector <Vector> p;
signed main() {
ios :: sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
cin >> a >> b >> r;
static Vector w[5];
w[0] = Vector(-0.5 * b + r, 0.5 * a - r);
w[1] = Vector(0.5 * b - r, 0.5 * a - r);
w[2] = Vector(0.5 * b - r, -0.5 * a + r);
w[3] = Vector(-0.5 * b + r, -0.5 * a + r);
for(int i = 1 ; i <= n ; i ++) {
double x, y, tht;
cin >> x >> y >> tht;
x += eps, y += eps, tht += eps;
Vector tmp = Vector(x, y);
for(int j = 0 ; j < 4 ; j ++) { p.push_back(tmp + rtt(w[j], tht)); }
}
int sz = p.size() - 1;
sort(p.begin(), p.end());
static int st[233333], top = 0;
st[++ top] = 0, st[++ top] = 1;
auto ins = [&](int x) {
while(top >= 2 && ((p[st[top - 1]] - p[st[top]]) ^ (p[st[top]] - p[x])) <= 0) -- top;
st[++ top] = x;
};
double ans = 0;
for(int i = 2 ; i <= sz ; i ++) { ins(i); }
for(int i = 2 ; i <= top ; i ++) ans += (p[st[i]] - p[st[i - 1]]).dis();
st[top = 1] = sz, st[++ top] = sz - 1;
for(int i = sz - 2 ; ~i ; -- i) { ins(i); }
for(int i = 2 ; i <= top ; i ++) ans += (p[st[i]] - p[st[i - 1]]).dis();
ans += pi * 2 * r;
cout << fixed << setprecision(2) << ans << '\n';
return 0;
}