Featured image of post Codeforces Round #1093(Div.2)

Codeforces Round #1093(Div.2)

B

题目大意:Hector 正与西班牙信息学奥林匹克代表队一起在拉科鲁尼亚远足,但他非常想溜出去见他的朋友们 Gustavo、Esomer 和 Dani。为此,他需要穿过一条由 $n$ 个志愿者看守的道路,志愿者们站成一排,编号为 $1$ 到 $n$;第 $i$ 位志愿者负责看守位置 $i$。每个志愿者都有一个内部计时器。最初(第 0 秒),第 $i$ 位志愿者的计时器值为 $a_i$。每秒,所有计时器增加 1。一旦计时器达到 $m$,它会绕回到 0。具体来说,在第 $x$ 秒,第 $i$ 位志愿者的计时器显示值为 $(a_i + x) \pmod m$。第 $i$ 位志愿者只有在他们的计时器恰好为 0 时,才会看守位置 $i$。

数据范围:$1 \le t \le 10^4$,$2 \le n \le 2 \cdot 10^5$,$2 \le m \le 10^9$,$0 \le a_i < m$,$\sum n \le 2 \cdot 10^5$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
void solve() {
    ll n, m;
    cin >> n >> m;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    rep(i, 0, n - 1) { a[i] = m - a[i] % m; }
    int tem = 0;
    rep(i, 0, n - 1) {
        if (i == 0 || a[i] == a[i - 1])
            tem++;
        else
            tem = 1;
        if (tem >= m) {
            cout << "NO" << endl;
            return;
        }
    }
    cout << "YES" << endl;
    return;
}

C

题目大意:Roger 有 $p$ 根单位长度的线段,以及 $q$ 个 L 型拼块,每个 L 型拼块由两根单位长度的线段以直角拼接而成。 他想用所有这些线段与拼块(不能剩余)拼成一个 $n \times m$ 的网格。给定 $p$ 和 $q$,判断是否存在正整数 $n$ 和 $m$,使得用恰好 $p$ 根单位线段和 $q$ 个 L 型拼块(可以旋转)正好拼出一个 $n \times m$ 的网格。

数据范围:$1 \le t \le 100$,$1 \le p, q \le 10^8$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void solve() {
    ll p, q;
    cin >> p >> q;
    ll tem = 2 * p + 4 * q + 1;
    for (ll i = 3; i * i <= tem; i += 2) {
        if (tem % i != 0) continue;
        ll tem2 = tem / i;
        ll n = (i - 1) / 2, m = (tem2 - 1) / 2;
        if (q > min(n * (m + 1), m * (n + 1))) {
            continue;
        }
        cout << n << ' ' << m << endl;
        return;
    }
    cout << -1 << endl;
    return;
}

D1

题目大意:本题的简单版与困难版的区别在于最多允许的查询次数。本题允许的查询次数为 66 次。有一个长度为 $2n+1$ 的秘密数组 $a$,其中的元素都是 $1$ 到 $n$ 的整数。每个值恰好出现两次,只有一个值恰好出现三次。你的目标是找出那个出现三次的值对应的三个位置。为此,你最多可以进行 66 次如下操作: 1. 选择一个整数 $k$ 和一个由 $1$ 到 $2n+1$ 之间的 $k$ 个不同下标组成的数组 $s$。2. 你会得到一个答案:在 $a_{s_1}, a_{s_2}, \ldots, a_{s_k}$ 中,有多少个值恰好出现一次。换句话说,就是没有重复出现的数字有多少种。3 出现了 2 次,2 出现了 3 次,这些都属于出现多次,不被计算。

数据范围:$1 \le t \le 500$,$2 \le n \le 1000$。

思路:

 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
54
55
56
57
58
59
60
61
void ask(int l, vi res) {
    cout << "? " << l << ' ';
    rep(i, 0, l - 1) cout << res[i] << ' ';
    cout << endl;
    cout.flush();
}
void report(ll x, ll y, ll z) {
    cout << "! " << x << ' ' << y << ' ' << z << '\n';
    cout.flush();
}
void solve() {
    int n;
    cin >> n;
    int l = 1, r = 2 * n + 1, mid;
    ll x, y, z;
    int op;
    auto check = [&](vi& res) -> bool {
        int cnt = sz(res);
        ask(cnt, res);
        cin >> op;
        if ((cnt - op) % 2 == 1)
            return true;
        else
            return false;
    };
    while (l <= r) {
        mid = (l + r) / 2;
        vi tem;
        rep(i, 1, mid) tem.push_back(i);
        if (check(tem)) {
            r = mid - 1;
            x = mid;
        } else
            l = mid + 1;
    }
    l = 1, r = 2 * n + 1;
    while (l <= r) {
        mid = (l + r) / 2;
        vi tem;
        frep(i, 2 * n + 1, mid) tem.push_back(i);
        if (check(tem)) {
            y = mid;
            l = mid + 1;
        } else
            r = mid - 1;
    }
    l = y + 1, r = x - 1;
    while (l <= r) {
        mid = (l + r) / 2;
        vi tem;
        rep(i, 1, mid) tem.push_back(i);
        tem.push_back(x);
        if (check(tem)) {
            r = mid - 1;
            z = mid;
        } else
            l = mid + 1;
    }
    report(x, y, z);
    return;
}

D2

题目大意:简单版与困难版的区别在于允许的查询次数上限不同。本题中最多允许进行 $33$ 次查询。存在一个隐藏数组 $a$,长度为 $2n+1$,其中元素取值为 $1$ 到 $n$ 的整数。每个值恰好出现两次,但有且仅有一个值恰好出现三次。需要找出这个出现三次的值对应的三个位置。你可以进行最多 $33$ 次如下形式的查询: 1. 选择一个整数 $k$,以及一个长度为 $k$ 的数组 $s$,其中包含 $1$ 到 $2n+1$ 之间的互不相同的下标。2. 你会得到一个数值,表示在 $a_{s_1}, a_{s_2}, \ldots, a_{s_k}$ 中,恰好出现一次的不同数值的个数(也就是说,没有重复的数的个数)。

数据范围:$1 \le t \le 500$,$2 \le n \le 1000$,$\sum n \le 2 \times 10^4$。

思路:

 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
54
55
56
57
58
59
60
61
void ask(int l, vi res) {
    cout << "? " << l << ' ';
    rep(i, 0, l - 1) cout << res[i] << ' ';
    cout << endl;
    cout.flush();
}
void report(ll x, ll y, ll z) {
    cout << "! " << x << ' ' << y << ' ' << z << '\n';
    cout.flush();
}
void solve() {
    int n;
    cin >> n;
    int l = 1, r = 2 * n + 1, mid;
    ll x, y, z;
    int op;
    auto check = [&](vi& res) -> bool {
        int cnt = sz(res);
        ask(cnt, res);
        cin >> op;
        if ((cnt - op) % 2 == 1)
            return true;
        else
            return false;
    };
    while (l <= r) {
        mid = (l + r) / 2;
        vi tem;
        rep(i, 1, mid) tem.push_back(i);
        if (check(tem)) {
            r = mid - 1;
            x = mid;
        } else
            l = mid + 1;
    }
    l = 1, r = 2 * n + 1;
    while (l <= r) {
        mid = (l + r) / 2;
        vi tem;
        frep(i, 2 * n + 1, mid) tem.push_back(i);
        if (check(tem)) {
            y = mid;
            l = mid + 1;
        } else
            r = mid - 1;
    }
    l = y + 1, r = x - 1;
    while (l <= r) {
        mid = (l + r) / 2;
        vi tem;
        rep(i, 1, mid) tem.push_back(i);
        tem.push_back(x);
        if (check(tem)) {
            r = mid - 1;
            z = mid;
        } else
            l = mid + 1;
    }
    report(x, y, z);
    return;
}