QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#879889#9520. Concave Hull2317663977WA 176ms23952kbC++2321.3kb2025-02-02 17:13:552025-02-02 17:13:55

Judging History

This is the latest submission verdict.

  • [2025-02-02 17:13:55]
  • Judged
  • Verdict: WA
  • Time: 176ms
  • Memory: 23952kb
  • [2025-02-02 17:13:55]
  • Submitted

answer

#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <cmath>
#include <cstring>
#include <iomanip>

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 - y) < 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>
	double 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;
	}

	// 计算两向量构成的三角形面积*2
	template<typename T>
	T area_triangle2(const Point<T>& A, const Point<T>& B, const Point<T>& C) {
		return abs(cross(B - A, C - A));
	}

	// 计算两向量构成的三角形有向面积*2
	template<typename T>
	T area_triangle2(const Vector<T>& A, const Vector<T>& B) {
		return abs(cross(A, B));
	}

	// 向量旋转	
	/*
		特殊情况是旋转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:夹角为平角,即方向相反
		auto _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
		auto a = x.p1;
		auto b = x.p2;
		auto c = y.p1;
		auto 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 (auto& i : p) ch.push_back(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 double& 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;
		}

		// 多边形的面积*2
		T Area2() {
			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);
		}

		// 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 double& angle) const { return area() * angle / 360.0; }
		friend ostream& operator<<(ostream& out, const Circle<T>& a) {
			out << "(" << a.c << ", " << a.r << ")";
			return out;
		}
	};
}
using namespace Geo;
using ll = long long;

const int N = 1e5 + 10;
int n;

void solve()
{
	cin >> n;
	auto p = vector<Point<ll>>();
	set<Point<ll>> se;
	for (int i = 1;i <= n;i++)
	{
		int x, y;
		cin >> x >> y;
		p.push_back(Point<ll>(x, y));
		se.insert(Point<ll>(x, y));
	}
	auto poly = convex_hull(p);
	if (poly.size() == n)
	{
		cout << -1 << '\n';
		return;
	}
	ll ans = poly.Area2();
	for (auto it : poly)
		se.erase(it);
	p.clear();
	for (auto it : se)
		p.push_back(it);
	auto poly2 = convex_hull(p);
	int m1 = poly.size(), m2 = poly2.size();
	int pos = 0;
	ll mn = 1e18;
	for (int i = 0;i < m2;i++)
	{
		if (area_triangle2(poly[0], poly[1], poly2[i]) < mn)
		{
			pos = i;
			mn = area_triangle2(poly[0], poly[1], poly2[i]);
		}
	}
	for (int i = 1;i < m1;i++)
	{
		ll mn2 = area_triangle2(poly[i], poly[(i + 1) % m1], poly2[pos % m2]);
		while (area_triangle2(poly[i], poly[(i + 1) % m1], poly2[(pos + 1) % m2]) < mn2)
		{
			mn2 = area_triangle2(poly[i], poly[(i + 1) % m1], poly2[(pos + 1) % m2]);
			pos++;
		}
		mn = min(mn, mn2);
	}
	cout << ans - mn << '\n';
}


int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}
	return 0;
}

詳細信息

Test #1:

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

input:

2
6
-2 0
1 -2
5 2
0 4
1 2
3 1
4
0 0
1 0
0 1
1 1

output:

40
-1

result:

ok 2 lines

Test #2:

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

input:

10
243
-494423502 -591557038
-493438474 -648991734
-493289308 -656152126
-491185085 -661710614
-489063449 -666925265
-464265894 -709944049
-447472922 -737242534
-415977509 -773788538
-394263365 -797285016
-382728841 -807396819
-373481975 -814685302
-368242265 -818267002
-344482838 -833805545
-279398...

output:

2178418010787347715
1826413114144932145
1651687576234220014
1883871859778998985
2119126281997959892
894016174881844630
2271191316922158910
1998643358049669416
1740474221286618711
1168195646932543192

result:

ok 10 lines

Test #3:

score: 0
Accepted
time: 34ms
memory: 3712kb

input:

1000
125
64661186 -13143076
302828013 -185438065
-418713797 -191594241
430218126 -397441626
354327250 -836704374
149668812 -598584998
311305970 66790541
199720625 -592356787
468137 -584752683
258775829 96211747
-358669612 -134890109
-129221188 -998432368
-277309896 -140056561
356901185 420557649
-51...

output:

1986320445246155278
1900093336073022078
1612088392301142476
2012259136539173407
1819942017252118749
1772230185841892196
1164835025329039520
1527446155241140517
1807368432185303666
1236918659444944569
1306839249967484778
1984123720246784099
1868728080720036006
667458140583450322
2127932992585026491
4...

result:

ok 1000 lines

Test #4:

score: 0
Accepted
time: 41ms
memory: 3584kb

input:

10000
9
484630042 51929469
-40468396 -517784096
98214104 -103353239
629244333 -475172587
106398764 153884485
49211709 -44865749
1 10
166321833 -247717657
406208245 668933360
13
548702216 -631976459
37150086 -292461024
707804811 -486185860
239775286 -903166050
10096571 -541890068
686103484 558731937
...

output:

950319193795831919
1661025342421008544
1285164852091455548
1159924751776806668
1206071151805176722
794021230296144371
699991678992587791
1133990718508584290
1486311831172661605
984875884297072200
1327767982175057345
758247019006396699
1355381234262206155
1139262078529131471
1613462877860621700
12392...

result:

ok 10000 lines

Test #5:

score: 0
Accepted
time: 79ms
memory: 5200kb

input:

100
439
471536154 -312612104
155692036 -937312180
-461624056 -357636609
236656684 -911414873
-288656914 -74788431
-465779694 -381475149
-334197401 -903065737
491513067 -447615916
337664889 -852236281
-281689379 -53519178
-159101704 -920779200
-326159514 -95396204
21868593 -994282736
488425383 -41046...

output:

1973162724053130487
2054612790507830954
1726805687754843724
1699420177872986528
2129388571309147631
2198295137903288810
1697185883164440272
1219697450095721478
2027023581922285255
1674691247127206655
1673105966817209954
2179188692918747442
2146544318743443141
2230356305133660648
1676850321902993764
...

result:

ok 100 lines

Test #6:

score: 0
Accepted
time: 56ms
memory: 5164kb

input:

100
1362
-467257672 -466669
-467054869 -478108
-466973270 -481776
-466556983 -499770
-466329414 -508693
-466248017 -511805
-466158865 -513786
-466101273 -515035
-465927700 -518748
-465717624 -522106
-465303448 -528127
-465124548 -530726
-464649746 -536693
-464554872 -537799
-464478196 -538680
-46416...

output:

1666097696993497
1791366071767866
1806187278469532
1683419854733713
1685891971828916
1730190225081651
1787048201197565
1850308098208660
1710694884375502
1826363113637639
1816375352374659
2047431269497691
1549806516003854
1829438662895747
1678707854135065
1687423392883819
2121960009997761
16687219538...

result:

ok 100 lines

Test #7:

score: 0
Accepted
time: 34ms
memory: 14696kb

input:

2
62666
-486101704 -505730259
-486101698 -506082699
-486101689 -506111362
-486101682 -506126031
-486101528 -506293759
-486101259 -506556385
-486101196 -506613483
-486101154 -506648604
-486100935 -506831392
-486100631 -507083675
-486100470 -507199151
-486100233 -507368923
-486100193 -507397039
-48609...

output:

2178736946152219010
1825181940245096152

result:

ok 2 lines

Test #8:

score: 0
Accepted
time: 173ms
memory: 23952kb

input:

2
100000
301945097 76373292
467957663 -286424714
8245445 -597212507
-474204621 -708828667
184159460 105942538
443435905 -429212625
490658771 -382198656
82512047 -612522436
-228221388 -965890088
394789011 -145801151
-106120174 -528202395
428939626 -194437311
497429477 -527407728
365739746 -114818962
...

output:

2502889432701099511
2267250485735988121

result:

ok 2 lines

Test #9:

score: 0
Accepted
time: 176ms
memory: 21496kb

input:

2
100000
221128057 -975244780
-618765360 -785575858
422567455 -906331476
-988680318 -150037424
-929870145 367887908
-757813541 -652471177
291995621 -956419655
-785381507 619012026
468864522 -883270094
-588416522 808557973
859345881 511394814
988105866 153775152
216931298 -976186873
467050734 8842305...

output:

6283183114882825575
6283183188903854361

result:

ok 2 lines

Test #10:

score: -100
Wrong Answer
time: 1ms
memory: 3584kb

input:

7
5
-1000000000 -1000000000
1000000000 -1000000000
1000000000 1000000000
1 0
-1 0
5
1000000000 1000000000
-1000000000 -1000000000
-2 0
-1 0
1 -1
6
1000000000 1000000000
-1000000000 -1000000000
-3 0
-1 0
0 -1
1 -1
4
-1000000000 -1000000000
1000000000 -1000000000
1000000000 1000000000
-1000000000 1000...

output:

4000000000000000000
7000000000
9000000001
-1
7000000000000000000
7999999998000000000
-1

result:

wrong answer 5th lines differ - expected: '6000000002000000000', found: '7000000000000000000'