1 条题解

  • 0
    @ 2025-5-5 13:50:25

    题解

    问题分析

    本题要求计算经过多次折叠后切割纸张展开后的片数。关键在于模拟折叠过程对切割线的影响,通过几何变换确定切割线在展开后纸张上的所有可能位置,进而计算这些位置与原纸张的交点及交点间的分割关系。

    关键思路

    折叠的几何变换:每次折叠相当于将纸张沿折叠线做镜像反射。切割线在折叠后的位置可通过对称变换反向展开,得到其在原纸张上的所有可能位置。 对称变换:点关于直线的对称点计算是核心,通过直线的一般式 Ax+By+C=0Ax+By+C=0 推导对称点坐标。 收集所有切割线:从最后一次折叠开始反向处理,每次折叠会引入对称的切割线,收集所有可能的切割线位置。 交点计算:计算每条切割线与原纸[0,1]×[0,1][0,1]×[0,1]的有效线段,统计这些线段之间的交点数,片数为交点数加 11。 #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
    上传者