2024 jscpc B题 Area of the Devil 题解
题目链接:Area of the Devil
算不在题目说的区域内的面积,直接算是比较麻烦的,这里给一个朋友直接算画的图,其实画出区域以后也算好算,当然官解提到的容斥去算更好写。
一共有五个空余的区域,我们考虑这五个区域怎么计算,图一是直接画出的所有区域的并集,图二则是五角星处于边界情况时,图上的三角形+弓形 即为某一块的未入并集区域,即非魔鬼区域。算出交点以后,就是最基本的初高中数学问题了,三角形面积可以用矢量来算,弓形面积的话,初中问题,圆心固定的,然后改为算对应的扇形-三角形即可,由于题目给出了夹角度数,所以可以考虑直接使用正弦定理算面积。稍微注意下边界怎么取的,结合图一图二,我们发现,从左往右依次数四个点,前两个取圆弧起点,另外两个取圆弧终点,然后交叉匹配就是组成的区域和直线了。尽量用矢量做计算,如果算出直线方程,可能直线斜率不存在,所以尽量用矢量计算交点。
参照代码
#include <bits/stdc++.h>
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
// #define isPbdsFile
#ifdef isPbdsFile
#include <bits/extc++.h>
#else
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope>
#endif
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
template <typename T>
int disc(T* a, int n)
{
return unique(a + 1, a + n + 1) - (a + 1);
}
template <typename T>
T lowBit(T x)
{
return x & -x;
}
template <typename T>
T Rand(T l, T r)
{
static mt19937 Rand(time(nullptr));
uniform_int_distribution<T> dis(l, r);
return dis(Rand);
}
template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
return (a % b + b) % b;
}
template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
a %= c;
T1 ans = 1;
for (; b; b >>= 1, (a *= a) %= c) if (b & 1) (ans *= a) %= c;
return modt(ans, c);
}
template <typename T>
void read(T& x)
{
x = 0;
T sign = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-') sign = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
x *= sign;
}
template <typename T, typename... U>
void read(T& x, U&... y)
{
read(x);
read(y...);
}
template <typename T>
void write(T x)
{
if (typeid(x) == typeid(char)) return;
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 ^ 48);
}
template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
write(x), putchar(c);
write(c, y...);
}
template <typename T11, typename T22, typename T33>
struct T3
{
T11 one;
T22 tow;
T33 three;
bool operator<(const T3 other) const
{
if (one == other.one)
{
if (tow == other.tow) return three < other.three;
return tow < other.tow;
}
return one < other.one;
}
T3()
{
one = tow = three = 0;
}
T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
{
}
};
template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
if (x < y) x = y;
}
template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
if (x > y) x = y;
}
namespace Geometry2D
{
//精度
constexpr ld EXP = 1e-12;
//Π
const ld PI = acos(-1.0);
ld sign(const ld x)
{
if (!fabs(x)) return 0;
return x / fabs(x);
}
struct Point
{
ld x, y;
Point() = default;
Point(const ld x, const ld y) : x(x), y(y)
{
};
Point operator+(const Point other) const
{
return Point(x + other.x, y + other.y);
}
Point operator-(const Point other) const
{
return Point(x - other.x, y - other.y);
}
Point operator*(const ld k) const
{
return Point(x * k, y * k);
}
Point operator/(const ld k) const
{
return Point(x / k, y / k);
}
bool operator==(const Point other) const
{
return fabs(x - other.x) < EXP && fabs(y - other.y) < EXP;
}
bool operator<(const Point other) const
{
return x != other.x ? x < other.x : y < other.y;
}
};
//两点距离
inline ld Distance(const Point x, const Point y)
{
return hypot(x.x - y.x, x.y - y.y);
}
typedef Point Vector;
//点乘
inline ld Dot(const Vector A, const Vector B)
{
return A.x * B.x + A.y * B.y;
}
//模长
inline ld Len(const Vector A)
{
return sqrt(Dot(A, A));
}
//模长平方
inline ld Len2(const Vector A)
{
return Dot(A, A);
}
//两向量夹角度数
inline ld Angle(const Vector A, const Vector B)
{
return acos(Dot(A, B) / Len(A) / Len(B));
}
//叉乘
inline ld Cross(const Vector A, const Vector B)
{
return A.x * B.y - A.y * B.x;
}
//三点构成的平行四边形面积
inline ld Area2(const Point A, const Point B, const Point C)
{
return Cross(B - A, C - A);
}
//逆时针旋转度数
inline Vector Rotate(const Vector A, const ld rad)
{
return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * cos(rad) + A.y * sin(rad));
}
//法向量的单位向量
inline Vector Normal(const Vector A)
{
return Vector(-A.y / Len(A), A.x / Len(A));
}
//叉乘检验两向量是否重合
inline bool Parallel(const Vector A, const Vector B)
{
return fabs(Cross(A, B)) < EXP;
}
struct Line
{
Point p1, p2;
Line() = default;
//两点式
Line(const Point& p1, const Point& p2) : p1(p1), p2(p2)
{
}
//点斜式
Line(const Point& p, const ld angle)
{
p1 = p, p2 = p1 + (fabs(angle - PI / 2) < EXP ? Point(0, 1) : Point(1, tan(angle)));
}
//一般式
Line(const ld a, const ld b, const ld c)
{
if (fabs(a) < EXP) p1 = Point(0, -c / b), p2 = Point(1, -c / b);
else if (fabs(b) < EXP) p2 = Point(-c / a, 0), p2 = Point(-c / a, 1);
else p1 = Point(0, -c / b), p2 = Point(1, (-c - a) / b);
}
};
typedef Line Segment;
//点和直线的关系
inline int Point_line_relation(const Point p, const Line& v)
{
int c = Cross(p - v.p1, v.p2 - v.p1);
if (c < 0) return 1; //p在v的左侧
if (c > 0) return 2; //p在v的右侧
return 0; //p在v上
}
//点是否在线段上
inline bool Point_on_seg(const Point p, const Segment& v)
{
return fabs(Cross(p - v.p1, v.p2 - v.p1)) < EXP && Dot(p - v.p1, p - v.p2) <= 0;
}
//点到直线的距离
inline ld Dis_point_line(const Point p, const Line& v)
{
return fabs(Cross(p - v.p1, v.p2 - v.p1)) / Distance(v.p1, v.p2);
}
//点在直线上的投影
inline Point Point_line_proj(const Point p, const Line& v)
{
ld k = Dot(v.p2 - v.p1, p - v.p1) / Len2(v.p2 - v.p1);
return v.p1 + (v.p2 - v.p1) * k;
}
//点关于直线的对称点
inline Point Point_line_symmetry(const Point p, const Line& v)
{
Point q = Point_line_proj(p, v);
return Point(2 * q.x - p.x, 2 * q.y - p.y);
}
//点到线段的距离
inline ld Dis_point_seg(const Point p, const Segment& v)
{
if (Dot(p - v.p1, v.p2 - v.p1) < 0 || Dot(p - v.p2, v.p1 - v.p2) < 0)
return min(
Distance(p, v.p1), Distance(p, v.p2));
return Dis_point_line(p, v);
}
//两直线的位置关系
inline int Line_relation(const Line& v1, const Line& v2)
{
if (Cross(v1.p2 - v1.p1, v2.p2 - v2.p1) < EXP)
{
if (fabs(Point_line_relation(v1.p1, v2)) < EXP) return 1; //重合
return 0; //平行
}
return 2; //相交
}
//两直线交点
inline Point Cross_point(const Point a, const Point b, const Point c, const Point d)
{
ld s1 = Cross(b - a, c - a);
ld s2 = Cross(b - a, d - a);
return Point(c.x * s2 - d.x * s1, c.y * s2 - d.y * s1) / (s2 - s1);
}
//两条线段是否相交
inline bool Cross_segment(const Point a, const Point b, const Point c, const Point d)
{
ld c1 = Cross(b - a, c - a), c2 = Cross(b - a, d - a);
ld d1 = Cross(d - c, a - c), d2 = Cross(d - c, b - c);
return sign(c1) * sign(c2) < 0 && sign(d1) * sign(d2) < 0; //1相交 0不相交
}
//点和多边形的关系
inline int Point_in_polygon(const Point pt, const Point* p, const int n)
{
forn(i, 0, n - 1) if (p[i] == pt) return 3; //在多边形的顶点上
forn(i, 0, n - 1)
{
Line v = Line(p[i], p[(i + 1) % n]);
if (Point_on_seg(pt, v)) return 2; //在多边形上
}
int num = 0;
forn(i, 0, n - 1)
{
int j = (i + 1) % n;
int c = sign(Cross(pt - p[i], p[i] - p[j]));
int u = sign(p[i].y - pt.y);
int v = sign(p[j].y - pt.y);
if (c > 0 && u < 0 && v >= 0) num++;
if (c < 0 && u >= 0 && v < 0) num--;
}
return num != 0;
}
//多边形面积
inline ld Polygon_area(const Point* p, const int n)
{
ld area = 0;
forn(i, 0, n - 1) area += Cross(p[i], p[(i + 1) % n]);
return area / 2;
}
//多边形重心
inline Point Polygon_center(const Point* p, const int n)
{
Point ans(0, 0);
if (!Polygon_area(p, n)) return ans;
forn(i, 0, n - 1) ans = ans + (p[i] + p[(i + 1) % n]) * Cross(p[i], p[(i + 1) % n]);
return ans / Polygon_area(p, n) / 6;
}
//求凸包,返回顶点,ans为凸包的顶点
inline int Convex_hull(Point* p, int n, Point* ans)
{
n = unique(p, p + n) - p;
sort(p, p + n);
int v = 0;
//下凸包
forn(i, 0, n - 1)
{
while (v > 1 && sign(Cross(ans[v - 1] - ans[v - 2], p[i] - ans[v - 1])) <= 0) v--;
ans[v++] = p[i];
}
int j = v;
//求上凸包
forv(i, n - 2, 0)
{
while (v > j && sign(Cross(ans[v - 1] - ans[v - 2], p[i] - ans[v - 1])) <= 0) v--;
ans[v++] = p[i];
}
if (n > 1) v--;
return v;
}
struct Circle
{
Point c; //圆心
ld r; //半径
Circle() = default;
Circle(const Point c, const ld r) : c(c), r(r)
{
}
Circle(const ld x, const ld y, const ld _r)
{
c = Point(x, y), r = _r;
}
};
//点到圆的关系
inline int Point_circle_relation(const Point p, const Circle& c)
{
ld dst = Distance(p, c.c);
if (sign(dst - c.r) < 0) return 0; //圆内
if (sign(dst - c.r) == 0) return 1; //圆上
return 2; //圆外
}
//直线和圆的关系
inline int Line_circle_relation(const Line& v, const Circle& c)
{
ld dst = Dis_point_line(c.c, v);
if (sign(dst - c.r) < 0) return 0; //圆内
if (sign(dst - c.r) == 0) return 1; //圆上
return 2; //圆外
}
//线段和圆的关系
inline int Seg_circle_relation(const Segment& v, const Circle& c)
{
ld dst = Dis_point_seg(c.c, v);
if (sign(dst - c.r) < 0) return 0; //圆内
if (sign(dst - c.r) == 0) return 1; //圆上
return 2; //圆外
}
//直线和圆的焦点.pa、pb是交点.返回值是交点的个数
inline int Line_cross_circle(const Line& v, const Circle& C, Point& pa, Point& pb)
{
if (Line_circle_relation(v, C) == 2) return 0; //无交点
Point q = Point_line_proj(C.c, v); //圆心在直线上的投影点
double d = Dis_point_line(C.c, v); //圆心到直线距离
double k = sqrt(C.r * C.r - d * d);
if (sign(k) == 0)
{
//一个交点
pa = q;
pb = q;
return 1;
}
Point n = (v.p2 - v.p1) / Len(v.p2 - v.p1); //单位向量
pa = q + n * k;
pb = q - n * k;
return 2; //两个交点
}
inline Point circle_center(const Point a, const Point b, const Point c)
{
Point center;
ld a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1 * a1 + b1 * b1) / 2;
ld a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2 * a2 + b2 * b2) / 2;
ld d = a1 * b2 - a2 * b1;
center.x = a.x + (c1 * b2 - c2 * b1) / d;
center.y = a.y + (a1 * c2 - a2 * c1) / d;
return center;
}
//最小覆盖圆
inline void min_cover_circle(Point* p, const int n, Point& c, ld& r)
{
random_shuffle(p, p + n);
c = p[0], r = 0;
forn(i, 1, n - 1)
{
if (sign(Distance(p[i], c) - r) > 0)
{
c = p[i], r = 0;
forn(j, 0, i - 1)
{
if (sign(Distance(p[j], c) - r) > 0)
{
c.x = (p[i].x + p[j].x) / 2;
c.y = (p[i].y + p[j].y) / 2;
r = Distance(p[j], c);
forn(k, 0, j - 1)
{
if (sign(Distance(p[k], c) - r) > 0)
{
c = circle_center(p[i], p[j], p[k]);
r = Distance(p[i], c);
}
}
}
}
}
}
}
}
namespace Geometry3D
{
//精度
constexpr ld eps = 1e-12;
//Π
const ld PI = acos(-1.0);
ld sgn(const ld x)
{
if (!fabs(x)) return 0;
return x / fabs(x);
}
////三维:点
struct Point3
{
ld x{}, y{}, z{};
Point3() = default;
Point3(const ld x, const ld y, const ld z) : x(x), y(y), z(z)
{
}
Point3 operator+(const Point3 B) const
{
return Point3{x + B.x, y + B.y, z + B.z};
}
Point3 operator-(const Point3 B) const
{
return Point3{x - B.x, y - B.y, z - B.z};
}
Point3 operator*(const double k) const
{
return Point3{x * k, y * k, z * k};
}
Point3 operator/(const double k) const
{
return Point3{x / k, y / k, z / k};
}
bool operator==(const Point3 B) const
{
return sgn(x - B.x) == 0 && sgn(y - B.y) == 0 && sgn(z - B.z) == 0;
}
};
typedef Point3 Vector3;
//点积.和二维点积函数同名.C++允许函数同名
inline ld Dot(const Vector3& A, const Vector3& B)
{
return A.x * B.x + A.y * B.y + A.z * B.z;
}
//叉积
inline Vector3 Cross(const Vector3& A, const Vector3& B)
{
return Point3{A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x};
}
inline ld Len(const Vector3& A)
{
return sqrt(Dot(A, A));
} //向量的长度
inline ld Len2(const Vector3& A)
{
return Dot(A, A);
} //向量长度的平方
//A、B的距离
inline ld Distance(const Point3& A, const Point3& B)
{
return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z));
}
//A与B的夹角
inline ld Angle(const Vector3& A, const Vector3& B)
{
return acos(Dot(A, B) / Len(A) / Len(B));
}
//三维:线
struct Line3
{
Point3 p1, p2;
Line3() = default;
Line3(const Point3& p1, const Point3& p2) : p1(p1), p2(p2)
{
}
};
typedef Line3 Segment3; //定义线段,两端点是Point p1,p2
//三维:三角形面积的两倍
inline ld Area2(const Point3& A, const Point3& B, const Point3& C)
{
return Len(Cross(B - A, C - A));
}
//三维:点到直线的距离
inline ld Dis_point_line(const Point3& p, const Line3& v)
{
return Len(Cross(v.p2 - v.p1, p - v.p1)) / Distance(v.p1, v.p2);
}
//三维:点在直线上
inline bool Point_line_relation(const Point3& p, const Line3& v)
{
return sgn(Len(Cross(v.p1 - p, v.p2 - p))) == 0 && sgn(Dot(v.p1 - p, v.p2 - p)) == 0;
}
//三维:点到线段的距离
inline ld Dis_point_seg(const Point3& p, const Segment3& v)
{
if (sgn(Dot(p - v.p1, v.p2 - v.p1)) < 0 || sgn(Dot(p - v.p2, v.p1 - v.p2)) < 0)
return min(
Distance(p, v.p1), Distance(p, v.p2));
return Dis_point_line(p, v);
}
//三维:点p在直线上的投影
inline Point3 Point_line_proj(const Point3& p, const Line3& v)
{
double k = Dot(v.p2 - v.p1, p - v.p1) / Len2(v.p2 - v.p1);
return v.p1 + (v.p2 - v.p1) * k;
}
//三维:平面
struct Plane
{
Point3 p1, p2, p3; //平面上的三个点
Plane() = default;
Plane(const Point3& p1, const Point3& p2, const Point3& p3) : p1(p1), p2(p2), p3(p3)
{
}
};
//平面法向量
inline Point3 PVec(const Plane& f)
{
return Cross(f.p2 - f.p1, f.p3 - f.p1);
}
//四点共平面
inline bool Point_on_plane(Point3 A, Point3 B, Point3 C, const Point3& D)
{
return sgn(Dot(PVec({A, B, C}), D - A)) == 0;
}
//两平面平行
inline int Parallel(const Plane& f1, const Plane& f2)
{
return Len(Cross(PVec(f1), PVec(f2))) < eps;
}
//两平面垂直
inline int Vertical(const Plane& f1, const Plane& f2)
{
return sgn(Dot(PVec(f1), PVec(f2))) == 0;
}
//直线与平面的交点p,返回值是交点的个数
inline int Line_cross_plane(const Line3& u, const Plane& f, Point3& p)
{
Point3 v = PVec(f); //平面的法向量
double x = Dot(v, u.p2 - f.p1);
double y = Dot(v, u.p1 - f.p1);
double d = x - y;
if (sgn(x) == 0 && sgn(y) == 0) return -1; //-1:v在f上
if (sgn(d) == 0) return 0; //0:v与f平行
p = (u.p1 * x - u.p2 * y) / d; //1:v与f相交
return 1;
}
//四面体有向面积*6
inline double volume4(const Point3& A, const Point3& B, const Point3& C, const Point3& D)
{
return Dot(Cross(B - A, C - A), D - A);
}
}
namespace Matrix
{
constexpr int NNN = 101;
ll MOD = 1e9 + 7;
struct Matrix
{
ll a[NNN][NNN];
Matrix operator*(const Matrix& other) const
{
Matrix ans;
memset(ans.a, 0, sizeof ans.a);
forn(i, 1, NNN - 1)
forn(j, 1, NNN - 1)
forn(k, 1, NNN - 1)
ans.a[i][j] = modt(
ans.a[i][j] + a[i][k] * other.a[k][j] % MOD, MOD);
return ans;
}
};
inline Matrix qpow(Matrix curr, ll k)
{
Matrix ans;
memset(ans.a, 0, sizeof ans.a);
forn(i, 1, NNN - 1) ans.a[i][i] = 1;
for (; k; k >>= 1, curr = curr * curr) if (k & 1) ans = ans * curr;
return ans;
}
}
namespace SuffixArray
{
constexpr int N = 1e6 + 10; //数组大小
constexpr int BUKSize = 128; //初始桶的个数
int sa[N], rnk[N], h[N]; //后缀数组
char s[N]; //字符串
int n; //字符串长
//两个类型
enum STR
{
L, S
};
//判断是否是LMS,当前位为S型,左边一位为L型
bool isLMS(auto type, int pos)
{
return !(pos == 0 || type[pos] != STR::S || type[pos - 1] != STR::L);
}
//判断是否是相等的LMS
bool isSameLMS(auto str, auto type, const int i, const int j)
{
if (i == -1 || j == -1) return false;
int k = -1;
while (true)
{
++k;
if (str[i + k] != str[j + k] || type[i + k] != type[j + k]) return false; //如果对应字符不等,或者类型不等
if (k == 0) continue;
if (isLMS(type, i + k) != isLMS(type, j + k)) return false;
if (isLMS(type, i + k)) return true;
}
}
//诱导排序LLLLLSSSSSS
void inSort(auto str, auto len, auto type, auto LMS, auto lmsSize, const int currBukSize)
{
auto buck = new int[currBukSize]; //桶
auto pre = new int[currBukSize]; //桶前缀和
memset(buck, 0, sizeof(buck[0]) * currBukSize);
memset(pre, 0, sizeof(pre[0]) * currBukSize);
memset(sa, -1, sizeof(int) * len);
forn(i, 0, len - 1) ++buck[str[i]]; //字符分桶
pre[0] = buck[0];
forn(i, 1, currBukSize - 1) pre[i] = pre[i - 1] + buck[i]; //前缀和
//先处理LMS(特殊的S型)到S桶里
forv(i, lmsSize - 1, 0) sa[--pre[str[LMS[i]]]] = LMS[i];
//正逆序扫,分S型和L型两种桶进行排序SSSSSSLLLLLLLL
//顺序处理L型
pre[0] = 0;
forn(i, 1, currBukSize - 1) pre[i] = pre[i - 1] + buck[i - 1];
forn(i, 0, len - 1) if (sa[i] > 0 && type[sa[i] - 1] == STR::L) sa[pre[str[sa[i] - 1]]++] = sa[i] - 1;
//逆序处理S型
pre[0] = buck[0];
forn(i, 1, currBukSize - 1) pre[i] = pre[i - 1] + buck[i]; //前缀和
forv(i, len - 1, 0) if (sa[i] > 0 && type[sa[i] - 1] == STR::S) sa[--pre[str[sa[i] - 1]]] = sa[i] - 1;
delete[] buck;
delete[] pre;
}
//SA-IS
void SA_IS(auto str, int len, auto LMS, int currBukSize)
{
auto type = new STR[N + 1];
//默认最后增加一个字符'#'比任何字符小,所以最后一个字符为S型
//处理类型
//前后相等用性质否则用定义
type[len - 1] = STR::S;
forv(i, len - 2, 0) type[i] = str[i] == str[i + 1] ? type[i + 1] : str[i] < str[i + 1] ? STR::S : STR::L;
int lmsSize = 0;
forn(i, 0, len - 1) if (isLMS(type, i)) LMS[lmsSize++] = i;
inSort(str, len, type, LMS, lmsSize, currBukSize); //诱导排序S型和L型
int pre = -1; //上一个sa[i]
int cnt = 0;
auto tmp = new int[len]; //临时存值数组
//记录还无法确定次序的LMS数组,还未确定次序就递归排序
forn(i, 0, len - 1)
{
if (!isLMS(type, sa[i])) continue;
if (!isSameLMS(str, type, pre, sa[i])) ++cnt;
tmp[sa[i]] = cnt - 1;
pre = sa[i];
}
auto nxtStr = new int[lmsSize];
lmsSize = 0;
//记录LMS
forn(i, 0, len - 1)
{
if (!isLMS(type, i)) continue;
nxtStr[lmsSize++] = tmp[i];
}
delete[] tmp;
auto nxtLMS = new int[lmsSize];
if (cnt < lmsSize) SA_IS(nxtStr, lmsSize, nxtLMS, cnt);
else
forn(i, 0, lmsSize - 1) sa[nxtStr[i]] = i;
delete[] nxtStr;
forn(i, 0, lmsSize - 1) nxtLMS[i] = LMS[sa[i]];
inSort(str, len, type, nxtLMS, lmsSize, currBukSize);
delete[] nxtLMS;
delete[] type;
}
inline void init(const int len)
{
n = len;
auto LMS = new int[n];
//加一个字符'#'
SA_IS(s, n + 1, LMS, BUKSize);
delete[] LMS;
forn(i, 0, n - 1) sa[i] = sa[i + 1] + 1;
forv(i, n - 1, 0) swap(sa[i], sa[i + 1]), swap(s[i], s[i + 1]);
sa[0] = sa[n + 1] = 0;
}
void get_h()
{
forn(i, 1, n) rnk[sa[i]] = i;
for (int i = 1, k = 0; i <= n; i++)
{
if (rnk[i] == 1) continue;
if (k) k--; //大于等于上一个后缀的h-1
int ear = sa[rnk[i] - 1]; //上一个后缀
while (i + k <= n && ear + k <= n && s[i + k] == s[ear + k]) k++;
h[rnk[i]] = k;
}
}
inline void clear()
{
forn(i, 0, n) sa[i] = rnk[i] = h[i] = 0;
forn(i, 0, n) s[i] = '\0';
}
}
using namespace Geometry2D;
// using namespace Geometry3D;
// using namespace Matrix;
// using namespace SuffixArray;
constexpr int T = 5;
constexpr int N = T + 10;
ld r, s[N], e[N];
inline ld getVal(const ld ans)
{
return ans * PI / 180;
}
inline int idx(const int curr)
{
if (curr <= 0) return curr + T;
if (curr > T) return curr - T;
return curr;
}
inline Point pos(const ld angle)
{
return Point(r * cos(angle), r * sin(angle));
}
inline ld getAngle(const ld ans)
{
if (ans < 0) return ans + 2 * PI;
return ans;
}
inline void solve()
{
cin >> r;
forn(i, 1, T) cin >> s[i], s[i] = getVal(s[i]);
forn(i, 1, T) cin >> e[i], e[i] = getVal(e[i]);
ld ans = 0;
forn(i, 1, T)
{
const int idx1 = i, idx2 = idx(i + 1), idx3 = idx(i - 1), idx4 = idx(i - 2);
const Point p1 = pos(s[idx1]);
const Point p2 = pos(s[idx2]);
const Point p3 = pos(e[idx3]);
const Point p4 = pos(e[idx4]);
//p1-p4 与 p2-p3 的交点
const Point point = Cross_point(p1, p4, p2, p3);
ans += fabs(Area2(p1, point, p3)) / 2; //三角形面积
const ld angele = getAngle(s[idx1] - e[idx3]); //夹角度数
ans += pow(r, 2) / 2 * (angele - sin(angele)); //弓形面积
}
cout << PI * pow(r, 2) - ans << endl;
}
signed int main()
{
Spider
//------------------------------------------------------
cout << fixed << setprecision(10);
int test = 1;
// read(test);
cin >> test;
forn(i, 1, test) solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
}
单次询问时间复杂度为:\(O(1)\)