跳转至

J - Press the Button

基本信息

题目出处2018 ICPC 亚洲区域赛青岛站网络赛
队伍通过率576/1550 (37.2%)

题解

\(l = \text{lcm}(a, c)\),显然每 \(l\) 秒的按键情况都是一样的。\(l\) 秒内 BaoBao 将会按键 \(\frac{c}{\text{gcd}(a, c)}\) 次(每次按 \(b\) 下),DreamGrid 将会按键 \(\frac{a}{\text{gcd}(a, c)}\) 次(每次按 \(d\) 下),因此直接模拟的复杂度是 \(\mathcal{O}(a + c)\)

  • \(t < l\),直接模拟每次按键。
  • \(t \ge l\),通过直接模拟,计算 \([0, l - 1]\) 这个时间段计数器增加的数值 \(x\),以及第 \(l\) 秒开始时 LED 是否还亮着(如果亮着,记 \(w = 1\),否则记 \(w = 0\))。之后再通过直接模拟,算出最后 \((t \bmod l)\) 秒计数器增加的数值 \(y\),则答案为 \((x + w) \times \lfloor \frac{t}{l} \rfloor + y\)

复杂度仍然为 \(\mathcal{O}(a + c)\)

参考代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long, bool> plb;

int a, b, c, d;
long long v, t;

// 直接模拟按键情况,
// 返回 [0, t] 这个时间段计数器增加的数值,
// 以及第 (t + 1) 秒开始时 LED 是否亮着
plb gao(long long t) {
    // cnt:计数器的值
    // tim:LED 最后亮到哪一秒
    long long cnt = 0, tim = -1;
    // now:现在的时间
    // x:BaoBao 下一次按键的时间
    // y:DreamGrid 下一次按键的时间
    long long now = 0, x = 0, y = 0;
    while (now <= t) {
        // BaoBao 按键
        if (now == x) {
            cnt += b - (now > tim ? 1 : 0);
            tim = now + v;
            x += a;
        }
        // DreamGrid 按键
        if (now == y) {
            cnt += d - (now > tim ? 1 : 0);
            tim = now + v;
            y += c;
        }
        // 前进到下一个按键的时刻
        now = min(x, y);
    }
    return plb(cnt, tim > t);
}

void solve() {
    scanf("%d%d%d%d%lld%lld", &a, &b, &c, &d, &v, &t);
    long long l = 1LL * a / gcd(a, c) * c;
    if (t < l) printf("%lld\n", gao(t).first);
    else {
        plb p1 = gao(l - 1);
        plb p2 = gao(t % l);
        printf("%lld\n", (p1.first + (p1.second ? 1 : 0)) * (t / l) + p2.first);
    }
}

int main() {
    int tcase; scanf("%d", &tcase);
    while (tcase--) solve();
    return 0;
}