1 条题解

  • 0
    @ 2026-5-16 22:47:03

    根据你提供的标程,这道题其实是一个数学规律题,而不是模拟题。
    因为球速极大(1010010^{100})且方向固定为 4545^\circ(即 dx,dy{1,1}d_x, d_y \in \{-1, 1\}),我们可以用“展开桌面法”或直接分析反射规律来简化问题。


    题目重述

    • 方形桌边长 ss,四角有袋口:(0,0),(0,s),(s,s),(s,0)(0,0),(0,s),(s,s),(s,0)
    • 球初始坐标 (xi,yi)(x_i, y_i)0<xi,yi<s0 < x_i, y_i < s
    • 初始方向 (dx,dy)(d_x, d_y)dx,dy{1,1}d_x, d_y \in \{-1, 1\}
    • 速度极大,反射完全弹性,角反射。
    • 问:最终有多少球会进任意一个袋口?

    关键观察

    由于反射是弹性的且方向始终为 4545^\circ,我们可以将运动“展开”为直线运动。

    1. 反射展开法

    将桌子无限反射展开成平面网格,每个原始桌子的镜像中,袋口位置为:

    • 主对角线方向 (1,1)(1,1)(1,1)(-1,-1) 的球,相当于在无限网格中沿直线运动,经过点:$$(x + k \cdot s,\; y + k \cdot s) \quad \text{或} \quad (x - k \cdot s,\; y - k \cdot s) $$
    • 副对角线方向 (1,1)(1,-1)(1,1)(-1,1) 的球,相当于沿直线运动,经过点:$$(x + k \cdot s,\; y - k \cdot s) \quad \text{或} \quad (x - k \cdot s,\; y + k \cdot s) $$

    2. 进袋条件

    在展开网格中,袋口位于所有坐标为 (ms,  ns)(m \cdot s,\; n \cdot s) 的点,其中 m,nm, n 为整数。

    情况 A:dx=dyd_x = d_y(主对角线方向)

    球轨迹为:

    $$(x + t,\; y + t) \quad (\text{若 } d_x = 1, d_y = 1) $$

    $$(x - t,\; y - t) \quad (\text{若 } d_x = -1, d_y = -1) $$

    为了进袋,需要存在某个 tt 使得:

    x±t=ms,y±t=nsx \pm t = m s,\quad y \pm t = n s

    两式相减得:

    xy=(mn)sx - y = (m - n) s

    因为 xy<s|x-y| < s(初始位置在内部),且 mnm-n 为整数,唯一可能是 m=nm=n,此时 x=yx=y

    因此进袋条件

    x=yx = y

    此时球沿主对角线运动,直接进 (0,0)(0,0)(s,s)(s,s) 袋。


    情况 B:dxdyd_x \neq d_y(副对角线方向)

    不妨设 dx=1,dy=1d_x = 1, d_y = -1,轨迹为:

    (x+t,  yt)(x + t,\; y - t)

    进袋要求:

    x+t=ms,yt=nsx + t = m s,\quad y - t = n s

    相加得:

    x+y=(m+n)sx + y = (m + n)s

    因为 0<x+y<2s0 < x+y < 2s,且 m+nm+n 为整数,唯一可能是 m+n=1m+n=1,此时:

    x+y=sx + y = s

    dx=1,dy=1d_x = -1, d_y = 1,轨迹为 (xt,  y+t)(x-t,\; y+t),同样可得 x+y=sx+y = s

    因此进袋条件

    x+y=sx + y = s

    此时球沿副对角线运动,进 (0,s)(0,s)(s,0)(s,0) 袋。


    算法

    对于每个球:

    • 如果 dx=dyd_x = d_yx=yx = y,则进球;
    • 如果 dxdyd_x \neq d_yx+y=sx + y = s,则进球;
    • 否则不进。

    时间复杂度O(n)O(n) 每个测试用例。


    代码验证(标程逻辑)

    #include <iostream>
    using namespace std;
    
    int main() {
        int t;
        cin >> t;
        while (t--) {
            int n, s, ans = 0;
            cin >> n >> s;
            for (int i = 0; i < n; i++) {
                int dx, dy, x, y;
                cin >> dx >> dy >> x >> y;
                if (dx == dy) {
                    if (x == y) ans++;
                } else {
                    if (x + y == s) ans++;
                }
            }
            cout << ans << '\n';
        }
        return 0;
    }
    

    示例验证

    样例 1

    n=1,s=2n=1, s=2,球:(1,1,1,1)(1,1,1,1)
    dx=dyd_x = d_yx=y=1x = y = 1 → 进球 → 输出 11

    样例 2

    n=5,s=4n=5, s=4

    1. (1,1,1,1)(1,-1,1,1)dxdyd_x \neq d_y1+1=241+1=2\neq 4 → 不进
    2. (1,1,2,2)(1,-1,2,2)2+2=4=s2+2=4=s → 进
    3. (1,1,2,3)(-1,1,2,3)2+3=542+3=5\neq 4 → 不进
    4. (1,1,1,3)(1,-1,1,3)1+3=4=s1+3=4=s → 进
    5. (1,1,3,1)(-1,1,3,1)3+1=4=s3+1=4=s → 进
      33 球 → 输出 33

    结论

    这道题的难点在于从复杂反射中抽象出简单的代数条件,而不是真的模拟 1010010^{100} 步。
    进球的唯一条件是球初始位于某条对角线且方向沿着该对角线向外

    • 1

    信息

    ID
    7139
    时间
    1000ms
    内存
    256MiB
    难度
    2
    标签
    递交数
    1
    已通过
    1
    上传者