1 条题解
-
0
题解
问题分析
本题要求计算经过多次折叠后切割纸张展开后的片数。关键在于模拟折叠过程对切割线的影响,通过几何变换确定切割线在展开后纸张上的所有可能位置,进而计算这些位置与原纸张的交点及交点间的分割关系。
关键思路
折叠的几何变换:每次折叠相当于将纸张沿折叠线做镜像反射。切割线在折叠后的位置可通过对称变换反向展开,得到其在原纸张上的所有可能位置。 对称变换:点关于直线的对称点计算是核心,通过直线的一般式 推导对称点坐标。 收集所有切割线:从最后一次折叠开始反向处理,每次折叠会引入对称的切割线,收集所有可能的切割线位置。 交点计算:计算每条切割线与原纸的有效线段,统计这些线段之间的交点数,片数为交点数加 。 #py import math
EPS = 1e-8
class Point: def init(self, x, y): self.x = x self.y = y
def __sub__(self, other): return Point(self.x - other.x, self.y - other.y) def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __mul__(self, k): return Point(self.x * k, self.y * k) def dot(self, other): return self.x * other.x + self.y * other.y def cross(self, other): return self.x * other.y - self.y * other.x def __eq__(self, other): return abs(self.x - other.x) < EPS and abs(self.y - other.y) < EPS def __hash__(self): return hash((round(self.x, 9), round(self.y, 9))) def __repr__(self): return f"({self.x:.6f}, {self.y:.6f})"
def line_from_points(p1, p2): a = p2.y - p1.y b = p1.x - p2.x c = p2.x * p1.y - p1.x * p2.y return (a, b, c)
def symmetric_point(p, a, b, c): d = a2 + b2 if d < EPS: return p x = p.x y = p.y tx = x - 2 * a * (ax + by + c) / d ty = y - 2 * b * (ax + by + c) / d return Point(tx, ty)
def segment_intersection(s1, s2): p, q, r, s = s1[0], s1[1], s2[0], s2[1] a = q - p b = s - r c = p - r cross_ab = a.cross(b) cross_ac = a.cross(c) cross_bc = b.cross(c)
if abs(cross_ab) < EPS: if abs(cross_ac) > EPS or abs(cross_bc) > EPS: return None else: points = [p, q, r, s] unique = list({p, q, r, s}) return unique if len(unique) > 1 else None t = cross_bc / cross_ab u = cross_ac / cross_ab if -EPS <= t <= 1 + EPS and -EPS <= u <= 1 + EPS: x = p.x + t * a.x y = p.y + t * a.y return Point(x, y) return None
def clip_segment(p1, p2): def inside(p): return 0 - EPS <= p.x <= 1 + EPS and 0 - EPS <= p.y <= 1 + EPS def compute_intersection(p, q, a, b, c): d = a * q.x + b * q.y + c if abs(d) < EPS: return q t = (-a * p.x - b * p.y - c) / d return Point(p.x + t * (q.x - p.x), p.y + t * (q.y - p.y))
clips = [ (lambda p: p.x >= -EPS, lambda p, q: compute_intersection(p, q, -1, 0, 0)), (lambda p: p.x <= 1 + EPS, lambda p, q: compute_intersection(p, q, 1, 0, -1)), (lambda p: p.y >= -EPS, lambda p, q: compute_intersection(p, q, 0, -1, 0)), (lambda p: p.y <= 1 + EPS, lambda p, q: compute_intersection(p, q, 0, 1, -1)), ] for cond, inter in clips: if cond(p1) and cond(p2): continue if cond(p1): p1, p2 = p2, p1 new_p = inter(p1, p2) if inside(new_p): p1 = new_p else: return None return (p1, p2)
def main(): import sys input = sys.stdin.read().split() ptr = 0 t = int(input[ptr]) ptr += 1 for _ in range(t): n = int(input[ptr]) ptr += 1 folds = [] for __ in range(n): x1, y1, x2, y2 = map(float, input[ptr:ptr+4]) ptr += 4 p1 = Point(x1, y1) p2 = Point(x2, y2) folds.append(line_from_points(p1, p2)) cx1, cy1, cx2, cy2 = map(float, input[ptr:ptr+4]) ptr += 4 cut_points = [Point(cx1, cy1), Point(cx2, cy2)] cut_lines = [cut_points]
for fold in reversed(folds): a, b, c = fold new_cuts = [] for cp in cut_lines: p1, p2 = cp sp1 = symmetric_point(p1, a, b, c) sp2 = symmetric_point(p2, a, b, c) new_cuts.append(cp) new_cuts.append([sp1, sp2]) cut_lines = new_cuts segments = [] for cp in cut_lines: p1, p2 = cp seg = clip_segment(p1, p2) if seg: segments.append(seg) points = set() for seg in segments: p1, p2 = seg points.add(p1) points.add(p2) intersections = set() for i in range(len(segments)): for j in range(i+1, len(segments)): seg1 = segments[i] seg2 = segments[j] p = segment_intersection(seg1, seg2) if p: intersections.add(p) total = len(intersections) + 1 print(total)
if name == "main": main()
- 1
信息
- ID
- 922
- 时间
- 1000ms
- 内存
- 30MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者