跳转至

J - Press the Button

基本信息

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

题解

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

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

复杂度仍然为 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;
}