QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#790694#6676. Computational GeometryLyniaAC ✓48ms19376kbC++2324.1kb2024-11-28 14:46:392024-11-28 14:46:39

Judging History

你现在查看的是最新测评结果

  • [2024-11-28 14:46:39]
  • 评测
  • 测评结果:AC
  • 用时:48ms
  • 内存:19376kb
  • [2024-11-28 14:46:39]
  • 提交

answer

///////////        
//                   //      //
//              ////////////////////
//                   //      //
//                 
///////////

//          
//          
//           //     //    ////////     /\     /////////
//           //     //   //      //          //       //
//            ////////   //      //    //    //       //
//                  //   //      //    //    //       //
//////////   ////////    //      //    //     /////////////

#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <list>
#include <stack>
#include <array>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <random>
#include <numeric>
#include <functional>
#include <optional>
//#include <Windows.h>

using namespace std;

#define fa(i,op,n) for (int i = op; i <= n; i++)
#define fb(j,op,n) for (int j = op; j >= n; j--)
#define pb push_back
#define HashMap unordered_map
#define HashSet unordered_set
#define var auto
#define all(i) i.begin(), i.end()
#define all1(i) i.begin() + 1,i.end()
#define endl '\n'
#define px first
#define py second

using VI = vector<int>;
using VL = vector<long long>;
using ll = long long;
using ull = unsigned long long;
using db = double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

template<class T1, class T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& p) {
	out << '(' << p.first << ", " << p.second << ')';
	return out;
}

template<typename T>
ostream& operator<<(ostream& out, const vector<T>& ve) {
	for (T i : ve)
		out << i << ' ';
	return out;
}

template<class T1, class T2>
ostream& operator<<(ostream& out, const map<T1, T2>& mp) {
	for (auto i : mp)
		out << i << '\n';
	return out;
}

template<typename ...T>
bool _debug(T... a) {
	((cout << a << ' '), ...);
	cout << endl;
	return -1;
}

const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int IINF = 0x7fffffff;
const int iinf = 0x80000000;
const ll LINF = 0x7FFFFFFFFFFFFFFF;
const ll linf = 0x8000000000000000;
int dx[8] = { 1, -1, 0, 0, 1, -1, 1, -1 };
int dy[8] = { 0, 0, 1, -1, 1, -1, -1, 1 };

//#include "Lynia.h"
namespace MyTools
{
	template <typename T>
	class Math;

	template <const int T>
	class ModInt;

	namespace Geo {
		template<typename T>
		class Point;

		template<typename T>
		class Line;

		template<typename T>
		class Polygon;

		template<typename T>
		class Circle;

		template<typename T>
		using Vector = Point<T>;

		template<typename T>
		using Segment = Line<T>;

		template<typename T>
		using PointSet = Polygon<T>;

		const double eps = 1e-9;
		const double PI = acos(-1.0);

		// 浮点数 x 的符号
		template<typename T>
		int sgn(T x) {
			if (fabs(x) < eps) return 0;
			return x > 0 ? 1 : -1;
		}

		// 比较两个浮点数
		template<typename T>
		int cmp(T x, T y) {
			if (fabs(x) < eps)return 0; // x == y,返回 0
			else return x < y ? -1 : 1; // x < y,返回 -1; x > y,返回 1
		}

		double radians(double degrees) {
			return degrees * PI / 180.0;
		}

		// 两点距离
		template<typename T>
		T dist(const Point<T>& A, const Point<T>& B) {
			return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
		}

		// 点积
		template<typename T>
		T dot(const Vector<T>& A, const Vector<T>& B) {
			// a · b = |a| |b| cos
			// 可用于判断两向量夹角
			return A.x * B.x + A.y * B.y;
		}

		// 叉积
		template<typename T>
		T cross(const Vector<T>& A, const Vector<T>& B) {
			// a · b = |a| |b| sin
			// 可以判断两向量的相对方向
			// 也能算两向量形成的平行四边形面积
			return A.x * B.y - A.y * B.x;
		}

		// 向量长度
		template<typename T>
		T len(const Vector<T>& A) {
			return sqrt(dot(A, A));
		}

		// 向量长度的平方
		template<typename T>
		T len2(const Vector<T>& A) {
			return dot(A, A);
		}

		// 两向量夹角
		template<typename T>
		double angle(const Vector<T>& A, const Vector<T>& B) {
			return acos(dot(A, B) / len(A) / len(B));
		}

		// 计算两向量构成的平行四边形有向面积
		// 三个点A、B、C,以A为公共点,得到2个向量B-A和C-A,它们构成的平行四边形
		template<typename T>
		T area_parallelogram(const Point<T>& A, const Point<T>& B, const Point<T>& C) {
			return abs(cross(B - A, C - A));
		}

		// 计算两向量构成的平行四边形面积
		// 两个有公共点的向量 A B 构成的平行四边形
		template<typename T>
		T area_parallelogram(const Vector<T>& A, const Vector<T>& B) {
			return abs(cross(A, B));
		}

		// 计算两向量构成的三角形面积
		// 三个点A、B、C,以A为公共点,得到2个向量B-A和C-A,它们构成的三角形
		template<typename T>
		T area_triangle(const Point<T>& A, const Point<T>& B, const Point<T>& C) {
			return abs(cross(B - A, C - A)) / 2.0;
		}

		// 计算两向量构成的三角形有向面积
		// 两个有公共点的向量 A B 构成的三角形
		template<typename T>
		T area_triangle(const Vector<T>& A, const Vector<T>& B) {
			return abs(cross(A, B)) / 2.0;
		}

		// 向量旋转	
		/*
			特殊情况是旋转90度:
			逆时针旋转90度:Rotate(A, pi/2),返回Vector(-A.y, A.x);
			顺时针旋转90度:Rotate(A, -pi/2),返回Vector(A.y, - A.x)。
		*/
		template<typename T>
		Vector<T> rotate(const Vector<T>& A, double rad) {
			return Vector<T>(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
		}

		// 有时需要求单位法向量,即逆时针转90度,然后取单位值。
		template<typename T>
		Vector<T> normal(const Vector<T>& A) {
			return Vector<T>(-A.y / len(A), A.x / len(A));
		}

		// 两个向量是否平行或重合
		template<typename T>
		bool parallel(const Vector<T>& A, const Vector<T>& B) {
			return sgn(cross(A, B)) == 0; // 返回true表示平行或重合
		}

		// 点和直线的位置关系
		template<typename T>
		int point_line_relation(const Point<T>& p, const Line<T>& v) {
			int c = sgn(cross(p - v.p1, v.p2 - v.p1));
			if (c < 0)return 1;              // 1 :p在v的左边
			if (c > 0)return 2;              // 2 :p在v的右边
			return 0;                        // 0 :p在v上
		}

		// 点和线段的位置关系
		template<typename T>
		bool point_segment_relation(const Point<T>& p, const Line<T>& v) {
			// 0 点不在线段v上
			// 1 点在线段v上

			// 前者为 True 说明 p 和 线段 v 的一个端点连边,和 v 本身的夹角为 0,即 p 在 直线 v 上
			// 后者为 True 说明 p 和两端点形成平角,也就是说 p 在两端点之间
			return sgn(cross(p - v.p1, v.p2 - v.p1)) == 0 && sgn(dot(p - v.p1, p - v.p2)) <= 0;
		}

		// 点到直线的距离
		template<typename T>
		double point_line_dis(const Point<T>& p, const Line<T>& v) {
			// 实际上是算了 p 和 v 的一个端点连边,然后和 v 形成的平行四边形的面积,除底得到
			return fabs(cross(p - v.p1, v.p2 - v.p1)) / dist(v.p1, v.p2);
		}

		// 点在直线上的投影
		template<typename T>
		Point<T> point_line_proj(const Point<T>& p, const Line<T>& v) {
			double k = dot(v.p2 - v.p1, p - v.p1) / len2(v.p2 - v.p1);
			return v.p1 + (v.p2 - v.p1) * k;
		}

		// 点关于直线的对称点
		template<typename T>
		Point<T> point_line_symmetry(const Point<T>& p, const Line<T>& v) {
			Point<T> q = point_line_proj(p, v);
			return Point<T>(2 * q.x - p.x, 2 * q.y - p.y);
		}

		// 点到线段的距离
		template<typename T>
		double point_segment_dis(const Point<T>& p, const Segment<T>& v) {
			// 先检查点 p 到线段 v 的投影是否在线段 v 上
			// 如果在,就直接返回点 p 到直线 v 距离
			// 如果不在,就返回线段 v 两端点里 p 

			// p 先和 v 的两端点比较,看看是否两向量夹角 > 90
			if (sgn(dot(p - v.p1, v.p2 - v.p1)) < 0 || sgn(dot(p - v.p2, v.p1 - v.p2)) < 0)
				return min(dist(p, v.p1), dist(p, v.p2)); // 点的投影不在线段上
			return point_line_dis(p, v);           // 点的投影在线段上
		}

		// 叉积判断两条向量的位置关系,AB * AC,两向量共点
		template<typename T>
		int vector_vector_relation(const Vector<T>& v1, const Vector<T>& v2) {
			int sign = sgn(cross(v1, v2));
			if (sign == 0)return 0; // 共线
			if (sign > 0)return 1;  // v2 在 v1 的逆时针方向 
			if (sign < 0)return 2;  // v2 在 v1 的顺时针方向 
		}

		// 叉积判断两条直线的位置关系
		template<typename T>
		int line_line_relation(const Line<T>& v1, const Line<T>& v2) {
			if (sgn(cross(v1.p2 - v1.p1, v2.p2 - v2.p1)) == 0) {
				if (point_line_relation(v1.p1, v2) == 0) return 1;  // 1: 重合
				else return 0;                                      // 0: 平行
			}
			return 2;                                               // 2: 相交
		}

		// 两向量夹角类型
		template<typename T>
		int vector_vector_angle_type(const Vector<T>& v1, const Vector<T>& v2) {
			// 0:夹角度为 0
			// 1:夹角为锐角
			// 2:夹角为钝角
			// 3:夹角为平角,即方向相反
			var _dot = dot(v1, v2);
			if (vector_vector_relation(v1, v2) == 0) { // 两向量共线
				if (sgn(_dot) > 0)return 0;
				else return 3;
			}
			else {
				if (sgn(_dot) > 0)return 1;
				else return 2;
			}
		}

		// 两条直线的交点
		template<typename T>
		Point<T> line_line_cross_point(const Point<T>& a, const Point<T>& b, const Point<T>& c, const Point<T>& d) {
			// Line1 : ab, Line2 : cd
			double s1 = cross(b - a, c - a);
			double s2 = cross(b - a, d - a);                    // 叉积有正负
			return Point<T>(c.x * s2 - d.x * s1, c.y * s2 - d.y * s1) / (s2 - s1);
		}

		// 两条直线的交点
		template<typename T>
		Point<T> line_line_cross_point(const Line<T>& x, const Line<T>& y) {
			// Line1 : ab, Line2 : cd
			var a = x.p1;
			var b = x.p2;
			var c = y.p1;
			var d = y.p2;
			double s1 = cross(b - a, c - a);
			double s2 = cross(b - a, d - a);                    // 叉积有正负
			return Point<T>(c.x * s2 - d.x * s1, c.y * s2 - d.y * s1) / (s2 - s1);
		}

		// 两个线段是否相交
		template<typename T>
		bool segment_segment_is_cross(const Point<T>& a, const Point<T>& b, const Point<T>& c, const Point<T>& d) {
			// Line1 : ab, Line2 : cd
			double c1 = cross(b - a, c - a), c2 = cross(b - a, d - a);
			double d1 = cross(d - c, a - c), d2 = cross(d - c, b - c);
			return sgn(c1) * sgn(c2) < 0 && sgn(d1) * sgn(d2) < 0;  // 1: 相交;0: 不相交
		}

		// 点和多边形的关系
		template<typename T>
		int point_polygon_relation(const Point<T>& pt, const Polygon<T>& p) {
			// 点pt,多边形 p
			int n = p.size();
			for (int i = 0; i < n; i++) { // 枚举点
				if (p[i] == pt)  return 3;  // 3:点在多边形的顶点上
			}
			for (int i = 0; i < n; i++) { // 枚举边
				Line<T> v = Line<T>(p[i], p[(i + 1) % n]);
				if (point_segment_relation(pt, v)) return 2; // 2:点在多边形的边上
			}

			// 通过射线法计算点是否在多边形内部 (具体原理可以看书)
			int num = 0;
			for (int i = 0; i < n; i++) {
				int j = (i + 1) % n;
				int c = sgn(cross(pt - p[j], p[i] - p[j]));
				int u = sgn(p[i].y - pt.y);
				int v = sgn(p[j].y - pt.y);
				if (c > 0 && u < 0 && v >= 0) num++;
				if (c < 0 && u >= 0 && v < 0) num--;
			}
			return num != 0; // 1:点在内部; 0:点在外部
		}

		// 计算多边形周长
		template<typename T>
		T polygon_perimeter(const Polygon<T>& p) {
			T ans = 0;
			int n = p.size();
			for (int i = 0; i < n; i++)
				ans += dist(p[i], p[(i + 1) % n]);
			return ans;
		}

		// 多边形的面积
		template<typename T>
		T polygon_area(const Polygon<T>& p) {
			/*
				注意面积存在 正负
				逆时针遍历点算出来就是正的
				顺时针遍历点算出来就是负的
			*/
			T area = 0;
			int n = p.size();
			for (int i = 0; i < n; i++)
				area += cross(p[i], p[(i + 1) % n]);
			return abs(area) / 2.0;
		}

		// 多边形的重心
		template<typename T>
		Point<T> polygon_center_point(const Polygon<T>& p) {        //求多边形重心
			Point<T> ans(0, 0);
			int n = p.size();
			if (polygon_area(p, n) == 0) return ans;
			for (int i = 0; i < n; i++)
				ans = ans + (p[i] + p[(i + 1) % n]) * cross(p[i], p[(i + 1) % n]);
			return ans / polygon_area(p, n) / 6;
		}

		/*
		   求凸包,凸包顶点放在ch中
		   凸多边形:是指所有内角大小都在 [0, 180] 范围内的简单多边形
		   凸包:在平面上能包含所有给定点的最小凸多边形叫做凸包
		*/
		template<typename T>
		Polygon<T> convex_hull(vector<Point<T>> p) {
			Polygon<T> ch;

			if (p.size() == 0 or p.size() == 1 or p.size() == 2) {
				for (var& i : p) ch.pb(i);
				return ch;
			}

			// Andrew 法:
			// 先对所有点排序
			// 求上下凸包 (查每个边相较于上一条边的拐弯方向)
			// 然后合并
			// 最后得到的点是按照原点的逆时针顺序的

			int n = p.size();
			n = unique(p.begin(), p.end()) - p.begin(); // 去除重复点    
			ch.resize(2 * n);
			sort(p.begin(), p.end());  // 对点排序:按 x 从小到大排序,如果 x 相同,按 y 排序    
			int v = 0;

			// 求下凸包,如果p[i]是右拐弯的,这个点不在凸包上,往回退
			for (int i = 0; i < n; i++) {
				while (v > 1 && sgn(cross(ch[v - 1] - ch[v - 2], p[i] - ch[v - 1])) <= 0)
					v--;
				ch[v++] = p[i];
			}

			// 求上凸包
			for (int i = n - 1, j = v; i >= 0; i--) {
				while (v > j && sgn(cross(ch[v - 1] - ch[v - 2], p[i] - ch[v - 1])) <= 0)
					v--;
				ch[v++] = p[i];
			}
			ch.resize(v - 1);
			return ch;
		}

		// 点和圆的关系,根据点到圆心的距离判断
		template<typename T>
		int point_circle_relation(const Point<T>& p, const Circle<T>& C) {
			double dst = dist(p, C.c);
			if (sgn(dst - C.r) < 0) return 0;       // 0: 点在圆内
			if (sgn(dst - C.r) == 0) return 1;      // 1: 圆上
			return 2;                               // 2: 圆外
		}

		// 直线和圆的关系,根据圆心到直线的距离判断
		template<typename T>
		int line_circle_relation(const Line<T>& v, const Circle<T>& C) {
			double dst = point_line_dis(C.c, v);
			if (sgn(dst - C.r) < 0) return 0;       // 0: 直线和圆相交
			if (sgn(dst - C.r) == 0) return 1;      // 1: 直线和圆相切
			return 2;                               // 2: 直线在圆外
		}

		// 线段和圆的关系,根据圆心到线段的距离判断
		template<typename T>
		int segment_circle_relation(const Segment<T> v, const Circle<T> C) {
			double dst = point_segment_dis(C.c, v);
			if (sgn(dst - C.r) < 0) return 0;       // 0: 线段在圆内
			if (sgn(dst - C.r) == 0) return 1;      // 1: 线段和圆相切
			return 2;                               // 2: 线段在圆外
		}

		//pa, pb是交点。返回值是交点个数
		template<typename T>
		int line_cross_circle(const Line<T>& v, const Circle<T>& C, Point<T>& p1, Point<T>& p2) {
			if (line_circle_relation(v, C) == 2)  return 0;    // 无交点
			Point<T> q = point_line_proj(C.c, v);              // 圆心在直线上的投影点
			double d = point_line_dis(C.c, v);                 // 圆心到直线的距离
			double k = sqrt(C.r * C.r - d * d);
			if (sgn(k) == 0) {                                 // 1个交点,直线和圆相切
				p1 = q;	p2 = q;	return 1;
			}
			Point<T> n = (v.p2 - v.p1) / len(v.p2 - v.p1);     // 单位向量
			p1 = q + n * k;  p2 = q - n * k;
			return 2;                                          // 2个交点
		}

		// 弧度制
		template<typename T>
		double circle_arc_area(const Circle<T>& c, const db& angle) {
			return c.area() * angle / 360.0;
		}

		template<typename T>
		double circle_area(const Circle<T>& c) {
			return c.area();
		}

		// atan2 极角排序,默认逆时针排序
		template<typename T>
		void angle_polar_sort_atan2(vector<Point<T>>& points, const Point<T>& reference = Point<T>(0, 0)) {
			sort(points.begin(), points.end(),
				[&](const Point<T>& a, const Point<T>& b)->bool
				{ return a.polar_angle(reference) < b.polar_angle(reference); });
		}

		// cross 极角排序,默认逆时针排序
		template<typename T>
		void angle_polar_sort_cross(vector<Point<T>>& points, const Point<T>& reference = Point<T>(0, 0)) {
			sort(points.begin(), points.end(),
				[&](Point<T> a, Point<T> b)->bool {
					a = a - reference; b = b - reference;
					if (a.quadrant() != b.quadrant())return a.quadrant() < b.quadrant();
					return sgn(cross(a, b)) > 0; // b 在 a 逆时针方向
				});
		}

		template<typename T>
		class Point {
		private:
			int id;

		public:
			T x, y;

			Point(T x = 0, T y = 0) : x(x), y(y), id(0) {}

			// this 点相较于 reference 点的极角
			// atan2 极角排序有时可能超时,有时反而更快
			double polar_angle(const Point<T>& reference = Point(0, 0)) const {
				return atan2(y - reference.y, x - reference.x);
			}

			T len() const { return sqrt(len2()); } // 向量长度
			T len2() const { return (*this) * (*this); } // 向量长度的平方

			// 求象限,包括了xy正负半轴
			// 可用于叉积法极角排序
			int quadrant() {
				if (x > 0 && y >= 0)return 1;      // 包含了 y 非负半轴
				else if (x <= 0 && y > 0)return 2; // 包含了 x 非正半轴
				else if (x < 0 && y <= 0)return 3; // 包含了 y 非正半轴
				else if (x >= 0 && y < 0)return 4; // 包含了 x 非负半轴
				else return 0; // 原点
			}

			bool hf() {
				return x > 0 || x == 0 && y > 0;
			}
			void set_id(int id) { this->id = id; }
			int get_id()const { return id; }

			Point operator- (const Point& B) const { return Point(x - B.x, y - B.y); }
			Point operator+ (const Point& B) const { return Point(x + B.x, y + B.y); }
			T operator^ (const Point<T>& B) const { return x * B.y - y * B.x; } // 叉积
			T operator* (const Point<T>& B) const { return x * B.x + y * B.y; } // 点积
			Point operator* (const T& B) const { return Point(x * B, y * B); }
			Point operator/ (const T& B) const { return Point(x / B, y / B); }
			bool operator< (const Point& B) const { return x < B.x || (x == B.x && y < B.y); }
			bool operator> (const Point& B) const { return x > B.x || (x == B.x && y > B.y); }
			bool operator== (const Point& B) const { return x == B.x && y == B.y; }
			bool operator!= (const Point& B) const { return !(*this == B); }

			friend ostream& operator<<(ostream& out, const Point& a) {
				out << '(' << a.x << ", " << a.y << ')';
				return out;
			}
		};

		template<typename T>
		class Line {
		public:
			Point<T> p1, p2;                         // 线上的两个点
			Line() {}
			Line(Point<T> p1, Point<T> p2) :p1(p1), p2(p2) {}
			Line(Point<T> p, double angle) {         // 根据一个点和倾斜角 angle 确定直线,0 <= angle < pi
				p1 = p;
				if (sgn(angle - PI / 2) == 0) { p2 = (p1 + Point<T>(0, 1)); }
				else { p2 = (p1 + Point<T>(1, tan(angle))); }
			}
			Line(double a, double b, double c) {     // ax + by + c = 0
				if (sgn(a) == 0) {
					p1 = Point<T>(0, -c / b);
					p2 = Point<T>(1, -c / b);
				}
				else if (sgn(b) == 0) {
					p1 = Point<T>(-c / a, 0);
					p2 = Point<T>(-c / a, 1);
				}
				else {
					p1 = Point<T>(0, -c / b);
					p2 = Point<T>(1, (-c - a) / b);
				}
			}
			friend ostream& operator<<(ostream& out, const Line<T>& a) {
				out << "[" << a.p1 << ", " << a.p2 << "]";
				return out;
			}

			// 计算斜率 k
			double k() const {
				if (sgn(p2.x - p1.x) == 0) { // 垂直线,斜率不存在
					throw runtime_error("Vertical line has undefined slope.");
				}
				return double(p2.y - p1.y) / (p2.x - p1.x);
			}

			// 计算截距 b
			double b() const {
				if (sgn(p2.x - p1.x) == 0) { // 垂直线,斜率不存在
					throw runtime_error("Vertical line does not have a y-intercept.");
				}
				double _k = k();
				return p1.y - _k * p1.x;
			}
		};

		template<typename T>
		class Polygon : public vector<Point<T>> {
		public:
			// 该类可以当点集用,也可以当多边形用。
			// 但注意传入点集不一定逆时针顺序,对于多边形可能需要极角排序

			Polygon() {}
			Polygon(int n) :vector<Point<T>>(n) {}

			// 多边形的周长
			T Perimeter() {
				T ans = 0;
				int n = this->size();
				for (int i = 0; i < n; i++)
					ans += dist((*this)[i], (*this)[(i + 1) % n]);
				return ans;
			}

			// 多边形的面积
			T Area() {
				T area = 0;
				int n = this->size();
				for (int i = 0; i < n; i++) {
					area += cross((*this)[i], (*this)[(i + 1) % n]);
				}
				return abs(area) / 2.0;
			}

			// atan2 极角排序,默认逆时针排序
			void Polar_angle_sort_atan2(const Point<T>& reference = Point<T>(0, 0)) {
				sort(this->begin(), this->end(),
					[&](const Point<T>& a, const Point<T>& b)->bool
					{ return a.polar_angle(reference) < b.polar_angle(reference); });
			}

			// cross 极角排序,默认逆时针排序
			void Polar_angle_sort_cross(const Point<T>& reference = Point<T>(0, 0)) {
				sort(this->begin(), this->end(),
					[&](Point<T> a, Point<T> b)->bool {
						a = a - reference; b = b - reference;
						if (a.quadrant() != b.quadrant())return a.quadrant() < b.quadrant();
						return sgn(cross(a, b)) > 0;
					});
			}

			friend ostream& operator<<(ostream& out, const Polygon<T>& a) {
				out << "[";
				for (int i = 0; i < a.size(); i++)
					out << a[i] << ",]"[i == a.size() - 1];
				return out;
			}
		};

		template<typename T>
		class Circle {
		public:
			Point<T> c;  // 圆心
			T r;         // 半径
			Circle() {}
			Circle(Point<T> c, T r) :c(c), r(r) {}
			Circle(T x, T y, T _r) { c = Point<T>(x, y); r = _r; }
			double area() const { return PI * r * r; }
			// 弧度制
			double arc_area(const db& angle) const { return area() * angle / 360.0; }
			friend ostream& operator<<(ostream& out, const Circle<T>& a) {
				out << "(" << a.c << ", " << a.r << ")";
				return out;
			}
		};
	}

}

namespace MT = MyTools;
using Math = MT::Math<ll>;
#define geo MT::Geo

const int mod = 1e9 + 7;
using mint = MT::ModInt<mod>;

const int N = 1e6 + 10;

void solve(int CASE)
{
	cout << fixed << setprecision(12);

	int n, k; cin >> n >> k;
	var p = geo::PointSet<long double>(2*n);
	fa(i, 1, n) {
		long double x, y; cin >> x >> y;
		p[i - 1] = { x,y };
		p[i - 1 + n] = { x,y };
	}

	long double ans = 0;

	// 上一个 bc
	var last_b = p[0];
	var last_c = p[k];
	var last_bc = geo::Line<long double>(last_b, last_c);
	var tmp = geo::Polygon<long double>();
	fa(i, 0, k)tmp.pb(p[i]);
	long double S = 0;
	if (tmp.size() > 2)S = tmp.Area();
	ans = S;

	// 找第一个 a 点
	int j = k;
	long double S2 = 0; // 单峰函数,现在的 dis 降了就找到最远点了
	while (j + 1 < 2 * n) {
		j++;
		var now = p[j];
		var now_S = geo::area_triangle(now, last_b, last_c);
		if (S2 < now_S) S2 = now_S;
		else {
			j--;
			break;
		}
	}
	var a = p[j];
	S2 = geo::area_triangle(a, last_b, last_c);
	ans += S2;
	//_debug(a, last_b, last_c, S, S2);


	fa(i, 1, n - 1) {
		var b = p[i];
		var c = p[i + k];
		var bc = geo::Line<long double>(b, c);

		var Sbob = geo::area_triangle(last_b, last_c, b);
		var Scoc = geo::area_triangle(c, last_c, b);

		S = S - Sbob + Scoc;

		var res = S;
		while (j < i + k)j++;
		a = p[j];
		S2 = geo::area_triangle(a, b, c);

		while (j + 1 < 2 * n) { // a 逆时针枚举不能到 b 点
			j++;
			var now = p[j];
			var now_S = geo::area_triangle(now, b, c);
			if (S2 < now_S) S2 = now_S;
			else {
				j--;
				break;
			}
		}

		a = p[j];
		res += S2;

		last_bc = bc;
		last_b = b;
		last_c = c;
		//_debug(a, b, c, S, Sbob, Scoc, S2);
		ans = max(res, ans);
	}
	cout << ans << endl;
	return;
}

int main()
{
	//SetConsoleOutputCP(CP_UTF8);
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int _ = 1;
	cin >> _;
	fa(i, 1, _)solve(i);
	return 0;
}

这程序好像有点Bug,我给组数据试试?

详细

Test #1:

score: 100
Accepted
time: 0ms
memory: 3728kb

input:

3
3 1
0 0
1 0
0 1
8 3
1 2
3 1
5 1
7 3
8 6
5 8
3 7
1 5
7 2
3 6
1 1
3 1
7 1
8 1
5 6
4 6

output:

0.500000000000
26.500000000000
20.000000000000

result:

ok 3 numbers

Test #2:

score: 0
Accepted
time: 0ms
memory: 3844kb

input:

1
4 2
-1000000000 -1000000000
1000000000 -1000000000
1000000000 1000000000
-1000000000 1000000000

output:

4000000000000000000.000000000000

result:

ok found '4000000000000000000.000000000', expected '4000000000000000000.000000000', error '0.000000000'

Test #3:

score: 0
Accepted
time: 37ms
memory: 3892kb

input:

14246
7 5
-999999980 -999999988
-999999979 -999999984
-999999978 -999999978
-999999979 -999999972
-1000000000 -999999998
-999999993 -1000000000
-999999984 -999999993
6 1
-999999987 -999999987
-999999993 -999999981
-999999998 -999999986
-1000000000 -999999996
-999999995 -1000000000
-999999986 -999999...

output:

230.500000000000
78.000000000000
173.000000000000
46.000000000000
161.500000000000
25.000000000000
224.000000000000
78.000000000000
42.000000000000
75.000000000000
113.500000000000
179.000000000000
227.000000000000
224.500000000000
459.500000000000
33.500000000000
323.000000000000
208.000000000000
1...

result:

ok 14246 numbers

Test #4:

score: 0
Accepted
time: 48ms
memory: 3804kb

input:

14244
6 4
-547850284 -481269250
-1000000000 -714647423
-533299247 -1000000000
656886478 -769438616
700263718 -430440203
106399420 -305601756
10 3
-466281822 506862192
-907094238 85058839
-1000000000 -281869646
-855490497 -478229011
-112167057 -1000000000
147495199 -983428035
704507845 -902383045
828...

output:

732791354437434402.500000000000
1492466916906283434.500000000000
1571608624804175410.000000000000
853722168331793629.500000000000
1841579555796117823.500000000000
186812625650844482.000000000000
1374931373816256616.000000000000
1396248766527417139.500000000000
300749428982044501.000000000000
1597680...

result:

ok 14244 numbers

Test #5:

score: 0
Accepted
time: 35ms
memory: 3904kb

input:

1000
100 84
-638427072 -696806030
-574275620 -741577840
-517724956 -779879773
-440790977 -831653888
-371696794 -867523797
-292070733 -904513365
-246157947 -920874374
-196125497 -936669098
-120139525 -960537360
-54479671 -978537127
-11534554 -987883373
26411313 -994847568
72263671 -1000000000
1168709...

output:

2901829084045602653.500000000000
327527198347053245.500000000000
1734256029955228808.000000000000
2416380865036326542.000000000000
935891084317887469.000000000000
2828414703961765312.000000000000
2101460694807832700.000000000000
2426931532374706265.000000000000
2679372534658023503.500000000000
27623...

result:

ok 1000 numbers

Test #6:

score: 0
Accepted
time: 33ms
memory: 4204kb

input:

100
1000 168
-808847262 -517721134
-803072067 -525448193
-798730847 -531136476
-796502549 -534032203
-791151313 -540928191
-786588703 -546785604
-782732315 -551644783
-780071973 -554976222
-774771946 -561591700
-769683918 -567839156
-769554831 -567997637
-766249149 -572042373
-759870835 -579831042
-...

output:

1028923552719996045.000000000000
2832301779860078526.000000000000
2848011247470070271.000000000000
2506790184987356823.500000000000
2622377875251076131.000000000000
2556381233480029365.500000000000
2780396909089778369.500000000000
1735531899101324156.500000000000
987263293126023982.000000000000
2933...

result:

ok 100 numbers

Test #7:

score: 0
Accepted
time: 35ms
memory: 5492kb

input:

10
10000 3930
374998960 871320826
374305646 871707307
373541784 872131442
372913079 872480119
372247815 872848960
372082544 872940283
371300533 873371391
370696772 873703715
369897687 874143282
369135422 874562333
368787728 874753324
368396307 874968013
367915968 875230945
367376687 875525844
367147...

output:

2095908706043761789.000000000000
2881509906421599358.000000000000
860651843537664107.000000000000
2225240521612313977.500000000000
911084696371304608.000000000000
2134470965837802211.000000000000
2924168382633125311.500000000000
1052994530795952349.500000000000
2555680635181519967.000000000000
27032...

result:

ok 10 numbers

Test #8:

score: 0
Accepted
time: 31ms
memory: 19376kb

input:

1
100000 91077
937469288 -231959258
937491476 -231891836
937502721 -231857664
937522226 -231798381
937545631 -231727224
937556752 -231693411
937581626 -231617767
937594048 -231579990
937605611 -231544822
937620487 -231499574
937644936 -231425160
937656870 -231388830
937680141 -231317975
937699154 -2...

output:

2889987064399269902.000000000000

result:

ok found '2889987064399269888.000000000', expected '2889987064399269888.000000000', error '0.000000000'