UVa 10627 Infinite Race

题目描述

有一条长度为 LLL 的无摩擦跑道 ABABAB ,两端分别是 AAABBB 。两名运动员分别从两端出发:

  • 运动员 111AAA 出发,速度恒为 uuu
  • 运动员 222BBB 出发,速度恒为 vvv

两人到达另一端时立即掉头(不计掉头时间),并持续无限比赛。在比赛过程中,他们会在途中相遇(迎面相遇或超越时),也可能在端点相遇。给定比赛时间 ttt ,求在时间 ttt 内他们相遇的总次数(包括途中相遇和端点相遇)。

输入格式

每个测试用例包含四个 323232 位有符号非负整数:
LLL uuu vvv ttt
其中 L≠0L \neq 0L=0 。输入以一行 0 0 0 0 结束(不处理)。输入文件共有 100181001810018 行数据。

输出格式

对每个测试用例,输出相遇次数。

样例输入

10 5 5 4
10 5 10 4
10 10 10 4
0 0 0 0

样例输出

2
3
4

题目分析

问题本质

这是一个典型的相遇问题,但有以下特殊之处:

  1. 无限往返运动:运动员到达端点后立即掉头继续运动。
  2. 多种相遇方式:包括迎面相遇、同向超越、端点相遇。
  3. 无限时间内的有限时间统计:需要计算在给定时间 ttt 内的总相遇次数。

关键观察

  1. 相对运动视角:将两个运动员的运动分解为相对运动。
  2. 两种相遇模式
    • 迎面相遇:当两人相向而行时相遇。
    • 同向超越:当速度较快的运动员追上速度较慢的运动员时。
  3. 端点相遇的特殊性:在端点相遇同时满足两种相遇模式的条件,需要特殊处理。

数学模型推导

1. 迎面相遇的条件

设第 kkk 次迎面相遇的时间为 tkt_ktk ,则有:
(u+v)⋅tk=(2k+1)⋅L (u + v) \cdot t_k = (2k + 1) \cdot L (u+v)tk=(2k+1)L
其中 k=0,1,2,…k = 0, 1, 2, \ldotsk=0,1,2,

推导:第一次迎面相遇发生在相对运动距离为 LLL 时,之后每次迎面相遇需要相对运动 2L2L2L 的距离。

在时间 ttt 内,满足条件的 kkk 的最大值为:
kmax⁡=⌊(u+v)⋅t−L2L⌋ k_{\max} = \left\lfloor \frac{(u+v) \cdot t - L}{2L} \right\rfloor kmax=2L(u+v)tL
但更好的表达方式是直接计算次数:
迎面相遇次数=⌊(u+v)⋅t+L2L⌋ \text{迎面相遇次数} = \left\lfloor \frac{(u+v) \cdot t + L}{2L} \right\rfloor 迎面相遇次数=2L(u+v)t+L

2. 同向超越的条件

假设 u≥vu \ge vuv (速度较大者在前或在后都可能发生超越)。设第 kkk 次同向超越的时间为 sks_ksk ,则有:
(u−v)⋅sk=(2k+1)⋅L (u - v) \cdot s_k = (2k + 1) \cdot L (uv)sk=(2k+1)L
其中 k=0,1,2,…k = 0, 1, 2, \ldotsk=0,1,2,

在时间 ttt 内,同向超越次数为:
同向超越次数=⌊(u−v)⋅t+L2L⌋ \text{同向超越次数} = \left\lfloor \frac{(u-v) \cdot t + L}{2L} \right\rfloor 同向超越次数=2L(uv)t+L

3. 重复计算的端点相遇

当两个运动员在端点相遇时,这个时间点同时满足:
(u+v)⋅t=(2k1+1)⋅L和(u−v)⋅t=(2k2+1)⋅L (u+v) \cdot t = (2k_1+1) \cdot L \quad \text{和} \quad (u-v) \cdot t = (2k_2+1) \cdot L (u+v)t=(2k1+1)L(uv)t=(2k2+1)L
这意味着端点相遇被计算了两次(一次作为迎面相遇,一次作为同向超越),需要减去一次。

端点相遇发生的条件是:
u−vgcd⁡(u,v) 是奇数 \frac{u-v}{\gcd(u,v)} \text{ 是奇数} gcd(u,v)uv 是奇数
此时需要减去的次数为:
⌊gcd⁡(u,v)⋅t+L2L⌋ \left\lfloor \frac{\gcd(u,v) \cdot t + L}{2L} \right\rfloor 2Lgcd(u,v)t+L

4. 特殊情况处理
  • u=0u = 0u=0v=0v = 0v=0 时,两个运动员都不动,永远不会相遇(除了初始时分别在两端,不算相遇),答案为 000
  • u=vu = vu=v 时,没有同向超越,只有迎面相遇。此时 (u−v)=0(u-v) = 0(uv)=0 ,公式依然适用。
  • u<vu < vu<v 时,交换 uuuvvv ,保证 u≥vu \ge vuv ,公式依然成立。

最终公式

总相遇次数为:
ans=⌊(u+v)⋅t+L2L⌋+⌊(u−v)⋅t+L2L⌋−重复部分 \texttt{ans} = \left\lfloor \frac{(u+v) \cdot t + L}{2L} \right\rfloor + \left\lfloor \frac{(u-v) \cdot t + L}{2L} \right\rfloor - \text{重复部分} ans=2L(u+v)t+L+2L(uv)t+L重复部分
其中重复部分为:
重复部分={⌊gcd⁡(u,v)⋅t+L2L⌋如果 u−vgcd⁡(u,v) 是奇数0否则 \text{重复部分} = \begin{cases} \left\lfloor \frac{\gcd(u,v) \cdot t + L}{2L} \right\rfloor & \text{如果 } \frac{u-v}{\gcd(u,v)} \text{ 是奇数} \\ 0 & \text{否则} \end{cases} 重复部分={2Lgcd(u,v)t+L0如果 gcd(u,v)uv 是奇数否则


解题思路

算法步骤

  1. 读入数据:循环读入 L,u,v,tL, u, v, tL,u,v,t ,直到 L=0L = 0L=0
  2. 特判零速度:如果 u=0u = 0u=0v=0v = 0v=0 ,输出 000 ,继续下一组数据。
  3. 确保 u≥vu \ge vuv:如果 u<vu < vu<v ,交换两者的值。
  4. 计算迎面相遇次数
    ans=⌊(u+v)⋅t+L2L⌋ \texttt{ans} = \left\lfloor \frac{(u+v) \cdot t + L}{2L} \right\rfloor ans=2L(u+v)t+L
  5. 加上同向超越次数
    ans+=⌊(u−v)⋅t+L2L⌋ \texttt{ans} += \left\lfloor \frac{(u-v) \cdot t + L}{2L} \right\rfloor ans+=2L(uv)t+L
  6. 减去重复计算的端点相遇
    • 计算 d=gcd⁡(u,v)d = \gcd(u, v)d=gcd(u,v)
    • 如果 (u−v)/d(u-v)/d(uv)/d 是奇数,则减去 ⌊d⋅t+L2L⌋\left\lfloor \frac{d \cdot t + L}{2L} \right\rfloor2Ldt+L
  7. 输出结果

时间复杂度

  • 每组数据只需要 O(1)O(1)O(1) 时间计算。
  • 主要操作是整数运算和一次 gcd⁡\gcdgcd 计算。
  • 总时间复杂度为 O(nlog⁡min⁡(u,v))O(n \log \min(u,v))O(nlogmin(u,v)) ,其中 nnn 是数据组数。

空间复杂度

  • 只需要常数空间存储变量。

注意事项

  1. 使用 646464 位整数(u+v)⋅t(u+v) \cdot t(u+v)t 可能超过 323232 位整数范围,需要使用 long long 类型。
  2. 整数除法C++\texttt{C++}C++ 中的整数除法是向零取整,但公式中的除法是向下取整。由于所有值都是非负整数,直接使用整数除法即可。
  3. gcd⁡\gcdgcd 计算:可以使用 __gcd 函数(C++ 标准库)或自己实现。

参考代码

// Infinite Race
// UVa ID: 10627
// Verdict: Accepted
// Submission Date: 2025-12-14
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

int main() {
    long long L, u, v, t;
    while (cin >> L >> u >> v >> t) {
        if (L == 0) break;
        if (u == 0 && v == 0) {
            cout << 0 << endl;
            continue;
        }
        // 确保 u >= v
        if (u < v) swap(u, v);
        long long ans = 0;
        // 迎面相遇次数
        ans += ((u + v) * t + L) / (2 * L);
        // 同向超越次数
        ans += ((u - v) * t + L) / (2 * L);
        // 减去重复计算的端点相遇
        long long d = __gcd(u, v);
        if ((u - v) / d % 2 != 0) ans -= (d * t + L) / (2 * L);
        cout << ans << endl;
    }
    return 0;
}

总结

本题是一个经典的相遇问题,但加入了往返运动和端点相遇的复杂情况。解题的关键在于:

  1. 分离两种相遇模式:迎面相遇和同向超越。
  2. 数学建模:将相遇时间表示为等差数列的形式。
  3. 处理重复计算:端点相遇同时满足两种模式的条件,需要减去重复计数。

通过数学推导得到简洁的公式,再结合整数运算实现高效的计算。代码实现简洁明了,时间复杂度低,能够快速处理大量输入数据。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值